go_队列
1、队列(queue)
1.1 队列的应用场景
银行排队叫号
1.2 队列介绍
队列是一个有序列表,可以用数组或链表来实现
遵循先入先出的原则。即:先存入队列的数据要先取出,后存入的要后取出
示意图:(使用数组模拟队列示意图)
1.3 数组模拟队列
1、队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下,其中maxSize
是该队列的最大容量
2、因为队列的输出、输入是分别从前后端处理的,因此需要两个变量front及rear分别记录队列前后端的下标,front会随着数据输入而改变,如下图所示:
3、先完成一个非环形的队列(数组来实现)
思路分析 :
代码实现:
package main
import (
"errors"
"fmt"
"os"
)
//创建一个队列结构体
type queue struct {
Maxsize int
array[5] int
front int //队列首部
rear int //队列尾部
}
//队列添加元素
func (this *queue) addqueue(val int)(err error){
//判断队列是否已满
if this.rear==this.Maxsize-1{
return errors.New("queue full")
}
this.rear++
this.array[this.rear]=val
return
}
//展示队列元素
func (this *queue) showqueue() (err error) {
fmt.Println("队列当前情况:")
//遍历front到rare的元素
//front不包含队首的元素
for i :=this.front+1;i < this.rear;i++{
fmt.Println("array[%d]=%d\n",i,this.array[i] )
}
return
}
//获取队列元素
func (this *queue) getqueue()(val int,err error){
//判断队列是否为空
if this.front == this.rear{
return -1,errors.New("quell emptry")
}
this.front++
val = this.array[this.front]
return val,err
}
func main(){
//1、先创建一个队列元素
queue :=&queue{
Maxsize :5,
front :-1, //队列首部
rear :-1, //队列尾部
}
var key string
var i int
for {
//1、add
fmt.Println("1、输入add,添加队列元素")
//2、get
fmt.Println("2、输入get,获取队列元素")
//3、show
fmt.Println("3、输入show,遍历队列元素")
fmt.Println("4、输入exit,遍历队列元素")
fmt.Scanln(&key)
switch key {
case "add":
fmt.Println("输入add入队列数")
fmt.Scanln(&i)
err := queue.addqueue(i)
if err !=nil{
fmt.Println("添加数据失败,err:",err.Error())
}else {
fmt.Println("加入队列成功")
}
case "get":
fmt.Println("输入get获取队列数")
val,err := queue.getqueue()
if err !=nil{
fmt.Println("获取数据失败,err:",err)
return
}else {
fmt.Println("取出的数据val:=",val)
}
case "show":
fmt.Println("输入show显示队列元素")
queue.showqueue()
case "exit":
os.Exit(0)
}
}
}
上面代码总结:
1、上面代码实现了基本的队列结构,但是没有有效地利用数组空间
2、思考,如何有效的利用数组空间
1.4数组模拟环形队列
思路:
1、尾索引的下一个为头索引时,表示队列满,即将队列容量空出一个作为约定,再做判断满的时候需要注意[tail+1]==head 表示队列满了
2、tail == head代表队列为空
3、初始化时,tail=0,head = 0
4、怎么统计该队列有多少个元素(tail + maxsize - head)% maxsize
代码实现:
package main
import (
"errors"
"fmt"
"os"
)
//环形队列
type cirequeue struct {
maxsize int
head int
tail int
arry [5]int
}
//入队列
func (this *cirequeue) Push(val int) (err error) {
if this.isFull() {
return errors.New("queue full")
}
//this.tail在队列尾部,但是包含最后的元素
this.arry[this.tail] = val
this.tail = (this.tail + 1) % this.maxsize
return
}
//出队列
func (this *cirequeue) Pop() (val int, err error) {
if this.isEmpty() {
return 0, errors.New("queue empty")
}
val = this.arry[this.head]
this.head = (this.head + 1) % this.maxsize
return
}
//遍历队列
func (this *cirequeue) listQueue() (val int) {
fmt.Println("环形队列情况如下:")
//取出当前队列的元素
size := this.size()
if size == 0 {
fmt.Println("队列为空")
}
//设计一个辅助变量,指向head
tmphead := this.head
for i := this.head; i < size; i++ {
fmt.Println("arr[%d]=%d\t", tmphead, this.arry[tmphead])
tmphead = (tmphead + 1) % this.maxsize
}
fmt.Println()
return
}
//判断队列是否已满(队列空出末尾的一个位置用作标志位)
func (this *cirequeue) isFull() bool {
return (this.tail+1)%this.maxsize == this.head
}
//判断队列是否为空
func (this *cirequeue) isEmpty() bool {
return this.head == this.tail
}
//取出队列中有多少元素
func (this *cirequeue) size() int {
//关键算法
return (this.tail + this.maxsize - this.head) % this.maxsize
}
func main() {
//初始化结构体
queue := &cirequeue{
maxsize: 5,
head: 0,
tail: 0,
}
var key string
var i int
for {
//1、add
fmt.Println("1、输入add,添加队列元素")
//2、get
fmt.Println("2、输入get,获取队列元素")
//3、show
fmt.Println("3、输入show,遍历队列元素")
fmt.Println("4、输入exit,遍历队列元素")
fmt.Scanln(&key)
switch key {
case "add":
fmt.Println("输入add入队列数")
fmt.Scanln(&i)
err := queue.Push(i)
if err != nil {
fmt.Println("添加数据失败,err:", err.Error())
} else {
fmt.Println("加入队列成功")
}
case "get":
fmt.Println("输入get获取队列数")
val, err := queue.Pop()
if err != nil {
fmt.Println("获取数据失败,err:", err)
return
} else {
fmt.Println("取出的数据val:=", val)
}
case "show":
fmt.Println("输入show显示队列元素")
queue.listQueue()
case "exit":
os.Exit(0)
}
}
}