队列
定义
队列是一种先进先出(First in first out, FIFO)的线性表,它只允许在一端进行插入操作,而在另一端进行删除操作。
允许插入的一端,称为队尾。
允许删除的一端,称为队头。
队列的顺序存储结构
基本上和线性表的顺序存储结构一致。
入队示意图:
出队示意图:
代码实现
package Queue
// 队列的接口
type MyQueue interface {
// 入队
Push(data interface{})
// 出队
Pop() interface{}
// 获取第一个元素
Front() interface{}
// 获取最后一个元素
End() interface{}
// 判断是否空
IsEmpty() bool
// 队列的大小
Size() int
// 清空
Clear()
}
// 队列
type Queue struct {
// 数据域
dataSource []interface{}
// 大小
theSize int
}
// 初始化队列
func NewQueue() *Queue {
// 初始化结构体
myQueue := new(Queue)
// 开辟内存空间
myQueue.dataSource = make([]interface{}, 0, 10)
// 初始化当前大小
myQueue.theSize = 0
return myQueue
}
// 入队
func (queue *Queue) Push(data interface{}) {
// 数据加入到数据域
queue.dataSource = append(queue.dataSource, data)
// 大小加1
queue.theSize++
}
// 出队
func (queue *Queue) Pop() interface{} {
// 为空
if queue.IsEmpty() {
return nil
}
// 第一个元素
data := stack.dataSource[0]
// 如果队列不止一个元素
if queue.Size() > 1 {
// 重设数据域
queue.dataSource = queue.dataSource[1:queue.Size()]
}
// 大小减去1
stack.currentsize--
return data
}
// 获取第一个元素
func (queue *Queue) Front() interface{} {
// 为空
if queue.Size() == 0 {
return nil
}
return queue.dataSource[0]
}
// 获取最后一个元素
func (queue *Queue) End() interface{} {
// 为空
if queue.Size() == 0 {
return nil
}
return queue.dataSource[queue.Size()-1]
}
// 判断是否空
func (queue *Queue) IsEmpty() bool {
return queue.theSize == 0
}
// 获取队列大小
func (queue *Queue) Size() int {
return queue.theSize
}
// 清空
func (queue *Queue) Clear() {
// 重新开辟内存空间
queue.dataSource = make([]interface{}, 0, 10)
// 重新初始化当前大小
queue.theSize = 0
}
时间复杂度
队列的顺序存储结构,在出队时,时间复杂度为O(n);
而在进行入队操作时,时间复杂度为O(1)。
循环队列
前言
普通的队列有可能出现“假溢出”的问题,那什么是“假溢出”呢?
事实上下标0和下标1的位置还空着呢,队尾已经去到了数组之外,这就是“假溢出”。
定义
解决“假溢出”的办法,就是后面满了,就再从头开始,也就是头尾相接的循环。
队列的头尾相接的顺序存储结构,称为循环队列。
代码实现
package CricleQueue
import "errors"
// 队列最大容量
const QueueSize = 4
// 循环队列
type CricleQueue struct {
// 数据域
data [QueueSize]interface{}
// 头指针
front int
// 尾指针
rear int
}
// 初始化循环队列
func InitQueue(myQueue *CricleQueue) {
// 头指针、尾指针
myQueue.front = 0
myQueue.rear = 0
}
// 入队
func Push(q *CricleQueue, data interface{}) error {
// 队列已满
if (q.rear+1)%QueueSize == q.front {
return errors.New("队列满了")
}
// 入队
q.data[q.rear] = data
// 头指针推进一个位置
q.rear = (q.rear + 1) % QueueSize
return nil
}
// 出队
func Pop(q *CricleQueue) (interface{}, error) {
// 空队列
if q.rear == q.front {
return nil, errors.New("队列为空")
}
// 取出第一个数据
res := q.data[q.front]
// 清空数据
q.data[q.front] = 0
// 头指针推进一个位置
q.front = (q.front + 1) % QueueSize
return res, nil
}
// 获取队列大小
func QueueLength(q *CricleQueue) int {
return (q.rear - q.front + QueueSize) % QueueSize
}
队列的链式存储结构
其实就是单链表,只不过只能尾进头出而已。
代码实现
package QueueLink
import "errors"
// 链式队列接口
type LinkQueue interface {
// 入队
Push(data interface{})
// 出队
Pop() (interface{}, error)
// 获取队列长度
Length() int
}
// 链式队列
type QueueLink struct {
// 头指针
front *Node
// 尾指针
rear *Node
}
// 链式队列结点
type Node struct {
value interface{}
pNext *Node
}
// 初始化链式队列
func NewQueueLink() *QueueLink {
return &QueueLink{}
}
// 入队
func (qLink *QueueLink) Push(data interface{}) {
// 新结点
newNode := &Node{
value: data,
pNext: nil,
}
// 如果队列为空
if qLink.front == nil {
qLink.front = newNode
qLink.rear = newNode
}
// 尾指针指向新结点
qLink.rear.pNext = newNode
// 尾指针设为新结点
qLink.rear = newNode
}
// 出队
func (qLink *QueueLink) Pop() (interface{}, error) {
// 如果队列为空
if qLink.front == nil {
return nil, errors.New("空队列")
}
// 备份头指针
qhead := qLink.front
// 只有一个结点
if qLink.front == qLink.rear {
qLink.front = nil
qLink.rear = nil
} else {
qLink.front = qLink.front.pNext
}
return qhead.value, nil
}
// 获取队列长度
func (qLink *QueueLink) Length() int {
// 备份头结点
pnext := qLink.front
// 初始化长度
length := 0
// 循环到末尾
for pnext.pNext != nil {
pnext = pnext.pNext
length++
}
return length
}
时间复杂度
循环队列和链队列的基本操作都是常数事件,即都为O(1)。