Go-队列

1. 队列的应用场景

 

2. 队列的介绍

1)队列是一个有序列表,可以用数组或是链表来实现。

2)遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出。

示意图:(使用数组模拟队列示意图)

 

3.数组模拟队列

1)队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组声明如下,其中maxSize是该队列的最大容量

2)因为队列的输出、输入是分别从前后端来处理的,因此需要两个遍历front及rear分别记录队列前后端的下标,front会随着数据输出而改变,而rear则是随着数据输入而改变。

3)先完成一个非环形的队列(数组来实现)

当我们将数据存入队列时,称为“addqueue”,addqueue的处理需要有两个步骤:

(1)将尾指针往后移:rear + 1,front == rear 【空】

(2)若尾指针rear小于等于队列的最大下标MaxSize-1,则将数据存入rear所指的数组元素中,否则无法存入数据。rear == MaxSize - 1【队列满】

思路分析:

 

单向队列的实现,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package main
import (
    "fmt"
    "errors"
    "os"
)
// 数组模拟队列
// 使用数组实现队列的思路
// 1. 创建一个数组array,是作为队列的一个字段
// 2. front初始化为-1
// 3. real表示队列尾部,初始化为-1
// 4. 完成队列的基本查找
// AddQueue  // 加入数据到队列
// GetQueue // 从队列取出数据
// showQueue // 显示队列
type Queue struct {
    maxSize int
    array [5]int // 数组 => 模拟队列
    front int // 表示指向队列首
    rear int // 表示指向队列的尾部
}
// 1. 添加数据到队列
func (this *Queue) AddQueue(val int) (err error) {
    // 先判断队列是否已满
    if this.rear == this.maxSize - 1 { // 重要的提示:0..........................此时rear是队列尾部,包含最后这个元素
        return errors.New("queue full")
    }
    this.rear++ // 将rear后移一位
    this.array[this.rear] = val
    return
}
// 2. 显示队列,找到队首,然后到遍历到队尾
func (this *Queue) ShowQueue() {
    fmt.Println("队列当前的情况是:")
    // this.front 不包含这个队首的元素
    for i := this.front + 1; i <= this.rear; i++ {
        fmt.Printf("array[%d]=%d \t", i,this.array[i])
    }
  
}
// 3. 从队列中取出数据
func (this *Queue) GetQueue() (val int,err error) {
    // 先判断队列是否为空
    if (*this).front == (*this).rear { // 队空
        return -1,errors.New("queue empty")
    }
    this.front++
    val = this.array[this.front]
    return val, err
}
func main() {
    // 先创建一个队列
    queue := &Queue{   // 这种形式的写法,下面要调用GetQueue就不能再写成(&queue).GetQueue()
        maxSize: 5,
        front: -1,
        rear: -1,
    }
    // 菜单
    var key string
    var val int
    for {
        fmt.Println("1. 输入add  表示添加数据到队列")
        fmt.Println("2. 输入get  表示从队列中获取数据")
        fmt.Println("3. 输入show 表示显示队列")
        fmt.Println("4. 输入exit 表示显示队列")
        fmt.Scanln(&key)
        switch key {
            case "add":
                fmt.Println("输入你要入队列数")
                fmt.Scanln(&val)
                err := queue.AddQueue(val)
                if err == nil {
                    fmt.Println("加入队列ok")
                } else {
                    fmt.Println(err.Error())
                }
            case "get":
                val, err := queue.GetQueue()
                if err != nil {
                    fmt.Println(err.Error())
                } else {
                    fmt.Println("从队列中取出了一个数=",val)
                }
            case "show":
                queue.ShowQueue()
            case "exit":
                os.Exit(0)
        }
    }
}

对上面代码的小结和说明:

1)上面代码实现了基本队列结构,但是没有有效的利用数组空间

2)请思考,如何使用数组,实现一个环形队列

数组模拟环形队列

对前面的数组模拟队列的优化,充分利用数组。因此将数组看作是一个环形的。(通过取模的方式来实现即可)

提醒:

1)尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意(tail + 1) % maxSize == head 【满】

2)tail == head 【空】

3)分析思路如下:

(1)什么时候表示队列满(tail + 1)% maxSize == head

(2)tail == head 表示空

(3)初始化时,tail == 0,head == 0

(4)怎么统计该队列有多少个元素(tail + maxSize - head)% maxSize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package main
import (
    "fmt"
    "errors"
    "os"
)
  
// 使用一个结构体管理队列
type CircleQueue struct {
    maxSize int
    array [5]int // 数组 => 模拟队列
    head int // 指向队首
    tail int // 指向队尾
}
// 0. 添加数据到环形队列
func (this *CircleQueue) Push(val int) (err error) {
    if this.IsFull() {
        return errors.New("CirleQueue full")
    }
    this.array[this.tail] = val // 把值给尾部
    this.tail = (this.tail + 1) % this.maxSize
    return
}
func (this *CircleQueue) Pop() (val int, err error) {
    if this.IsEmpty() {
        return -1,errors.New("CircleQueue empty")
    }
    // 取出
    val = this.array[this.head]
    this.head++
    return val, nil
}
// 2. 判断环形队列是否满了
func (this *CircleQueue) IsFull()bool {
    return (this.tail + 1) % this.maxSize == this.head
}
// 3. 判断环形队列是否为空
func (this *CircleQueue) IsEmpty() bool {
    return this.tail == this.head
}
// 4. 取出环形队列有多少个元素
func (this *CircleQueue) Size() int {
    return (this.tail + this.maxSize - this.head) % this.maxSize
}
  
// 5. 显示环形队列
func (this *CircleQueue) Show() {
    // 取出当前队列有多少个元素
    size := this.Size()
    if size == 0 {
        fmt.Println("队列为空")
    }
    // 设计一个辅助的变量,指向head
    tempHead := this.head
    for i := 0; i < size; i++ {
        fmt.Printf("arr[%d]=%d\t",tempHead,this.array[tempHead])
        tempHead = (tempHead + 1) % this.maxSize
    }
    fmt.Println()
}
  
func main() {
    var circleQueue = &CircleQueue{
        maxSize: 5,
        head: 0,
        tail: 0,
    }
    var key string
    var val int
    for {
        fmt.Println("1. 输入add  表示添加数据到环形队列")
        fmt.Println("2. 输入get  表示从环形队列中获取数据")
        fmt.Println("3. 输入show 表示显示环形队列")
        fmt.Println("4. 输入exit 表示退出操作环形队列")
        fmt.Scanln(&key)
        switch key {
            case "add":
                fmt.Println("输入添加到队列的数据:")
                fmt.Scanln(&val)
                err := circleQueue.Push(val)
                if err != nil {
                    fmt.Println(err.Error())
                } else {
                    fmt.Println("加入队列 ok")
                }
            case "get":
                val, err := circleQueue.Pop()
                if err != nil {
                    fmt.Println(err.Error())
                } else {
                    fmt.Println("从队列中取出了一个数=",val)
                }
            case "show":
                circleQueue.Show()
            case "exit":
                os.Exit(0)
        }
    }
}

  



感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章页面中给出作者和原文连接
posted @   南昌拌粉的成长  阅读(561)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示