《大话数据结构》学习笔记 —— 05 队列(golang实现)


队列


定义

队列是一种先进先出(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)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值