顺序队列
循环队列
队列(Queue)与栈都是线性存储结构,因此以常见的线性表如数组、链表作为底层的数据结构,特点:
- 先进先出(First In First Out)的原则,简称FIFO结构
- 队尾添加元素,队首删除元素
相关概念:
- 队头与队尾: 允许元素插入的一端称为队尾,允许元素删除的一端称为队头
- 入队:队列的插入操作
- 出队:队列的删除操作
顺序队列
顺序存储上的不足:每次从数组头部删除元素(出队)后,需要将头部以后的所有元素往前移动一个位置,这是一个时间复杂度为O(n)的操作:
可能有人说,把队首标志往后移动不就不用移动元素了吗?但那样会造成数组空间的“流失”。我们希望队列的插入与删除操作都是O(1)的时间复杂度,同时不会造成数组空间的浪费,我们应该使用循环队列
基于数组实现顺序队列 代码
package main
import (
"errors"
"fmt"
"os"
)
// 使用结构体管理队列
type Queue struct {
Maxsize int
array [5]int //数组 模拟队列
front int // 指向队列首部
real int // 指向队列 尾部
}
// 入队
func (this *Queue) Push(val int) (err error) {
// 判断队列是否满
if this.real == this.Maxsize-1 {
return errors.New("queue full")
}
this.real++
this.array[this.real] = val
return
}
// 显示队列
func (this *Queue) showQueue() {
for i := this.front + 1; i <= this.real; i++ {
fmt.Printf("%d\t", this.array[i])
}
fmt.Println()
}
// 出队
func (this *Queue) Pop() (val int, err error) {
if this.front == this.real {
return val, errors.New("queue empty")
}
this.front++
val = this.array[this.front]
return
}
func main() {
queue := &Queue{
Maxsize: 5,
front: -1,
real: -1,
}
var key string
var val int
for {
fmt.Printf("1、输入push 入队\n2、输入pop 出队\n3、输入show 显示队列\n4、输入eixt 表示退出\n")
fmt.Scanln(&key)
switch key {
case "push":
fmt.Println("请输入你要入队的数据:")
fmt.Scanln(&val)
err := queue.Push(val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("入队成功")
}
case "pop":
val, err := queue.Pop()
if err != nil {
fmt.Println(err)
} else {
fmt.Println("出队数值",val)
}
case "show":
queue.showQueue()
case "exit":
os.Exit(-1)
}
}
}
循环队列
它可以把数组看出一个首尾相连的圆环,删除元素时将队首标志往后移动,添加元素时若数组尾部已经没有空间,则考虑数组头部的空间是否空闲,如果是,则在数组头部进行插入
循坏队列的核心在队头指针和队尾指针的增加方式:
this.tail=(this.tail+1)%this.maxsize
this.head=(this.head+1)%this.
当队列为空时this.head = this.tail,当队列为满时也有this.head = this.tail造成了判断队列是空还是满的二义性
解决方法:
1.增加一个参数,使删除元素为1,插入元素为0
2.增加一个参数,记录队列的元素个数即长度
3.空出一个单元,令(this.tail+1)%this.maxsize == this.head为队列为满的条件,以此解决二义性
基于数组实现循坏队列 代码
package main
import (
"errors"
"fmt"
"os"
)
// 使用结构体管理队列
type CycleQueue struct {
maxsize int
array [5]int //数组
head int //队首
tail int //队尾
}
// 入队列
func (this *CycleQueue) Push(val int) error {
if this.IsFull() {
return errors.New("queue full")
}
this.array[this.tail] = val
this.tail=(this.tail+1)%this.maxsize
return nil
}
//出队列
func (this *CycleQueue) Pop() (val int, err error) {
if this.IsEmpty() {
return val, errors.New("queue empty")
}
val = this.array[this.head]
this.head=(this.head+1)%this.maxsize
return val, nil
}
//显示队列
func (this *CycleQueue) ShowQ() {
size := this.Size()
if size == 0 {
fmt.Println("queue is empty")
}
//辅助变量 指向head
tempHead := this.head
for i := 0; i < size; i++ {
fmt.Println(this.array[tempHead])
tempHead = (tempHead + 1) % this.maxsize
}
}
//判断循环队列是否为空
func (this *CycleQueue) IsEmpty() bool {
return this.tail == this.head
}
//判断循环队列是否满
func (this *CycleQueue) IsFull() bool {
return (this.tail+1)%this.maxsize == this.head
}
//统计队列元素 个数
func (this *CycleQueue) Size() int {
return (this.tail + this.maxsize - this.head) % this.maxsize
}
func main() {
queue := &CycleQueue{
maxsize: 5,
tail: 0,
head: 0,
}
var key string
var val int
for {
fmt.Printf("1、输入push 入队\n2、输入pop 出队\n3、输入show 显示队列\n4、输入eixt 表示退出\n")
fmt.Scanln(&key)
switch key {
case "push":
fmt.Println("请输入你要入队的数据:")
fmt.Scanln(&val)
err := queue.Push(val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("入队成功")
}
case "pop":
val, err := queue.Pop()
if err != nil {
fmt.Println(err)
} else {
fmt.Println("出队数值", val)
}
case "show":
queue.ShowQ()
case "exit":
os.Exit(-1)
}
}
}