循环队列
- 特征
使用的头尾索引永远都在底层数组长度下标范围内,如队列长度为10,那么底层数组长度为11,index范围[0,10] - 解决的问题
用非循环数组实现的队列在底层数组满的时候有数据搬移的操作,会影响入队操作;循环数组可以解决这个问题! - 与同样用数组实现的普通队列的区别
1. 循环队列需要专门占用数组的一个位置来作为尾结点标识,这个位置不能填充真实数据,所以实际使用的数组长度会加一。
2. 循环队列需要一个初始化方法,使用一个默认字符将底层数组初始化。
3. 循环队列在满队列时,在底层没有数据搬移操作,入队 T(n)=O(1)。 - Code
package main
import (
"fmt"
"strconv"
)
type LoopQueue struct {
Items []string //利用数组实现队列
Head uint16 //头索引,恒为0
Tail uint16 //尾索引
Len uint16 //限定队列长度
}
//队列初始化,将[底层数组]初始化
func (this *LoopQueue) Init() {
this.Len = this.Len + 1 //因为最后一个位置不能使用,所以len要比声明的大一
for i:=0;i<int(this.Len);i++ {
this.Items = append(this.Items, "")
}
}
//入列
func (this *LoopQueue) Enqueue(v interface{}){
if ((this.Tail+1) % this.Len) == this.Head {
fmt.Println("the queue is full!")
return
}
this.Items[this.Tail] = v.(string)
fmt.Printf("%s enqueued, now length: tail:%s \n",v, this.Tail)
this.Tail = (this.Tail+1) % this.Len
}
//出列
func (this *LoopQueue) Dequeue()interface{}{
if this.Head == this.Tail {
fmt.Println("the queue is empty!")
return nil
}
ret := this.Items[this.Head]
fmt.Printf("Dequeue: %s! the surplus len: head:%s \n", ret, this.Head)
this.Head = (this.Head+1) % this.Len
return ret
}
func main(){
Q := &LoopQueue{Len:10} //设定队列长度
Q.Init() //初始化队列
for i:=0;i<12;i++ { //12>10 会提示full
s := strconv.Itoa(i)
Q.Enqueue(s+s+s) //入列(但只能入10个)
}
for i:=0;i<3;i++ {
Q.Dequeue() //出列3个
}
for i:=0;i<12;i++ { //12>10 会提示full
s := strconv.Itoa(i)
Q.Enqueue(s+s+s) //入列12个(但只能入3个)
}
for i:=0;i<12;i++ {
Q.Dequeue() //出列12次(但只能出10个)
}
}
使用这种方式有个问题是,使用队列前需要调用一个初始化方法,且初始化方法时用一个默认字符将底层数组填满,实在不是一个好的办法。读者如有更好的想法,还请指教。