目录
队列(Queue),是具有一定操作限制的线性表。只能在一端插入,在另一端删除。
队列的抽象数据类型描述
数据对象集:一个有0或多个元素的线性表。
操作集:
队列的顺序存储结构组成:一个一维数组、一个记录队列头元素位置的变量front、一个记录队列尾元素的变量rear。
- type Queue struct {
- front int
- rear int
- queueArray [6]int
- }
- func initQueue() (queue *Queue) {
- //初始化队列
- queue = &Queue{
- front: 0,
- rear: -1,
- queueArray: [6]int{},
- }
- return queue
- }
- func (q *Queue) addQueue(v int) error {
- //判断队列是否已满
- if q.Rear+1 == q.MaxSize {
- return errors.New("队列已满")
- }
-
- q.Rear += 1 //队尾下标+1
- q.QueueArray[q.Rear] = v //数据插入队尾
-
- return nil
- }
- func (q *Queue) deleteQueue() (int, error) {
- //判断队列否为空
- if q.Rear-q.Front == -1 {
- return -1, errors.New("队列为空")
- }
-
- v := q.QueueArray[q.Front] //获取队列头部元素值
- q.Front += 1 //队头下标+1
-
- return v, nil
- }
- package main
-
- import (
- "errors"
- "fmt"
- )
-
- type Queue struct {
- Front int
- Rear int
- MaxSize int
- QueueArray [6]int
- }
-
- func main() {
- //初始化队列
- queue := initQueue()
-
- //队列最大能存储6个元素,最大队尾下标为5
- queue.addQueue(100)
- queue.addQueue(200)
- fmt.Println("入队两个元素")
- fmt.Printf("队列: %v, 队头front: %v, 队尾rear: %v\n", queue.QueueArray, queue.Front, queue.Rear)
-
- v, err := queue.deleteQueue()
- if err != nil {
- fmt.Println(err)
- } else {
- fmt.Printf("出队元素: %v, 队头front: %v, 队尾rear: %v\n", v, queue.Front, queue.Rear)
- }
-
- //入队5个元素
- for i := 1; i <= 5; i++ {
- err := queue.addQueue(i)
- if err != nil {
- fmt.Println(err)
- }
- }
- fmt.Printf("队列: %v, 队头front: %v, 队尾rear: %v\n", queue.QueueArray, queue.Front, queue.Rear)
- }
-
- //队列初始化
- func initQueue() (queue *Queue) {
- //初始化队列
- queue = &Queue{
- Front: 0,
- Rear: -1,
- MaxSize: 6,
- QueueArray: [6]int{},
- }
- return queue
- }
-
- //队列-入队
- func (q *Queue) addQueue(v int) error {
- //判断队列是否已满
- if q.Rear+1 == q.MaxSize {
- return errors.New("队列已满")
- }
-
- q.Rear += 1 //队尾下标+1
- q.QueueArray[q.Rear] = v //数据插入队尾
-
- return nil
- }
-
- //队列-出队
- func (q *Queue) deleteQueue() (int, error) {
- //判断队列否为空
- if q.Rear-q.Front == -1 {
- return -1, errors.New("队列为空")
- }
-
- v := q.QueueArray[q.Front] //获取队列头部元素值
- q.QueueArray[q.Front] = 0 //出队数据置为0
- q.Front += 1 //队头下标+1
-
- return v, nil
- }
经过多次的入队和出队,队尾会达到数组的限制,而对头会空出几个位置。为了更好地利用数组的空间,则引入循环队列的概念。
循环队列的实现与常规的使用数组实现的非循环队列的区别就在于,循环队列的出栈和入栈时的队front和rear的操作有所不同。
- func (q *Queue) addQueue(v int) error {
- //判断循环队列是否已满
- if q.Rear-q.Frount+1 == q.MaxSize {
- return errors.New("循环队列已满")
- }
-
- q.Rear += 1 //队尾下标+1
- q.QueueArray[q.Rear%q.MaxSize] = v //数据入队尾;rear与MaxSize去模,获取实际数组下标
-
- return nil
- }
- func (q *Queue) deleteQueue() (int, error) {
- //判断循环队列否为空
- if q.Rear-q.Frount == -1 {
- return -1, errors.New("队列为空")
- }
-
- v := q.QueueArray[q.Frount%q.MaxSize] //获取队列头部元素值;front与MaxSize去模,获取实际数组下标
- q.QueueArray[q.Frount%q.MaxSize] = 0 //出队数据置为0
- q.Frount += 1 //队头下标+1
-
- return v, nil
- }
- package main
-
- import (
- "errors"
- "fmt"
- )
-
- type Queue struct {
- Frount int
- Rear int
- MaxSize int
- QueueArray [6]int
- }
-
- type QueueNode struct {
- }
-
- func main() {
- //初始化队列
- queue := initQueue()
-
- //队列最大能存储6个元素,最大队尾下标为5
- queue.addQueue(100)
- queue.addQueue(200)
- fmt.Println("入队两个元素")
- fmt.Printf("队列: %v, 队头front: %v, 队尾rear: %v\n", queue.QueueArray, queue.Frount, queue.Rear)
-
- v, err := queue.deleteQueue()
- if err != nil {
- fmt.Println(err)
- } else {
- fmt.Printf("出队元素: %v, 队头front: %v, 队尾rear: %v\n", v, queue.Frount, queue.Rear)
- }
-
- //循环:入队2个元素,出队一个元素
- fmt.Println("---循环:入队2个元素,出队一个元素---")
- for i := 1; i <= 5; i++ {
- fmt.Printf("第%v次循环:\n", i)
- err := queue.addQueue(i)
- if err != nil {
- fmt.Println(err)
- break
- }
- fmt.Printf("队列: %v, 队头front: %v, 队尾rear: %v\n", queue.QueueArray, queue.Frount, queue.Rear)
-
- err = queue.addQueue(i)
- if err != nil {
- fmt.Println(err)
- break
- }
- fmt.Printf("队列: %v, 队头front: %v, 队尾rear: %v\n", queue.QueueArray, queue.Frount, queue.Rear)
-
- queue.deleteQueue()
- fmt.Printf("队列: %v, 队头front: %v, 队尾rear: %v\n", queue.QueueArray, queue.Frount, queue.Rear)
- }
- }
-
- //队列初始化
- func initQueue() (queue *Queue) {
- //初始化队列
- queue = &Queue{
- Frount: 0,
- Rear: -1,
- MaxSize: 6,
- QueueArray: [6]int{},
- }
- return queue
- }
-
- //队列-入队
- func (q *Queue) addQueue(v int) error {
- //判断循环队列是否已满
- if q.Rear-q.Frount+1 == q.MaxSize {
- return errors.New("循环队列已满")
- }
-
- q.Rear += 1 //队尾下标+1
- q.QueueArray[q.Rear%q.MaxSize] = v //数据入队尾;rear与MaxSize去模,获取实际数组下标
-
- return nil
- }
-
- //队列-出队
- func (q *Queue) deleteQueue() (int, error) {
- //判断循环队列否为空
- if q.Rear-q.Frount == -1 {
- return -1, errors.New("队列为空")
- }
-
- v := q.QueueArray[q.Frount%q.MaxSize] //获取队列头部元素值;front与MaxSize去模,获取实际数组下标
- q.QueueArray[q.Frount%q.MaxSize] = 0 //出队数据置为0
- q.Frount += 1 //队头下标+1
-
- return v, nil
- }
如果用非循环队列,数组容量为6,rear为5时就无法再入队元素了。使用了循环队列,只要数组中还有空间,就可以一直循环入队元素。上述例子中rear最终达到了10,也就是一共有11个元素成功入队,充分利用了空间。
队列也可以使用一个单链表实现。插入和删除操作分别在链表的两端进行。
链表的特点是:在链表的头部,做插入、删除操作都方便;在链表的尾部,做插入操作方便,做删除操作不方便。
- //队列-链式存储结构-结构体
- type LinkQueue struct {
- Frount *QueueNode
- Rear *QueueNode
- }
-
- //队列-链式存储结构-每个结点结构体
- type QueueNode struct {
- data int
- next *QueueNode
- }
- func initQueue() (queue *LinkQueue) {
- //初始化队列
- queue = &LinkQueue{
- Frount: nil,
- Rear: nil,
- }
- return queue
- }
- func (lq *LinkQueue) addQueue(v int) {
- //链式存储结构,暂不考虑队列是否已满
-
- //新建入队节点
- newNode := &QueueNode{
- data: v,
- next: nil,
- }
-
- //如果Frount为空,表明为入队的第一个节点
- if lq.Frount == nil {
- lq.Frount = newNode
- lq.Rear = newNode
- }
-
- //原队尾指向新入队节点
- lq.Rear.next = newNode
- lq.Rear = newNode
- }
- func (lq *LinkQueue) deleteQueue() (int, error) {
- //判断循环队列否为空
- if lq.Frount == nil {
- return -1, errors.New("队列为空")
- }
-
- v := lq.Frount.data //获取队列头部元素值
- lq.Frount = lq.Frount.next //frount指向下一个结点
-
- return v, nil
- }
- package main
-
- import (
- "errors"
- "fmt"
- )
-
- type LinkQueue struct {
- Frount *QueueNode
- Rear *QueueNode
- }
-
- type QueueNode struct {
- data int
- next *QueueNode
- }
-
- func main() {
- //初始化队列
- queue := initQueue()
-
- //循环入队&出队
- fmt.Println("---入队---")
- for i := 100; i <= 105; i++ {
- queue.addQueue(i)
- fmt.Println("入队元素:", queue.Rear.data)
- }
-
- fmt.Println("---出队---")
- for queue.Frount != nil {
- v, err := queue.deleteQueue()
- if err != nil {
- fmt.Println(err)
- } else {
- fmt.Println("出队元素:", v)
- }
- }
- }
-
- //队列初始化
- func initQueue() (queue *LinkQueue) {
- //初始化队列
- queue = &LinkQueue{
- Frount: nil,
- Rear: nil,
- }
- return queue
- }
-
- //队列-入队
- func (lq *LinkQueue) addQueue(v int) {
- //链式存储结构,暂不考虑队列是否已满
-
- //新建入队节点
- newNode := &QueueNode{
- data: v,
- next: nil,
- }
-
- //如果Frount为空,表明为入队的第一个节点
- if lq.Frount == nil {
- lq.Frount = newNode
- lq.Rear = newNode
- }
-
- //原队尾指向新入队节点
- lq.Rear.next = newNode
- lq.Rear = newNode
- }
-
- //队列-出队
- func (lq *LinkQueue) deleteQueue() (int, error) {
- //判断循环队列否为空
- if lq.Frount == nil {
- return -1, errors.New("队列为空")
- }
-
- v := lq.Frount.data //获取队列头部元素值
- lq.Frount = lq.Frount.next //frount指向下一个节点
-
- return v, nil
- }