数据结构【Golang实现】(六)——队列

队列

1. 顺序队列

1.1 结构定义

type SequentialQueue struct {
	Items  []any  // 队列元素
	Length uint64 // 队列元素个数
	Cap    uint64 // 队列容量
}

// NewSequentialQueue 初始化队列
func NewSequentialQueue(cap uint64) *SequentialQueue {
	return &SequentialQueue{
		Items:  make([]any, 0, cap),
		Length: 0,
		Cap:    cap,
	}
}

1.2 IsEmpty()

// IsEmpty 判断队列是否为空
func (queue *SequentialQueue) IsEmpty() bool {
	return queue.Length == 0
}

1.3 IsFull()

// IsFull 判断队列是否为满
func (queue *SequentialQueue) IsFull() bool {
	return queue.Length == queue.Cap
}

1.4 Push()

// Push 将元素添加到该队列末尾
func (queue *SequentialQueue) Push(item any) {
	if queue.IsFull() {
		fmt.Println("队列已满")
		return
	}
	queue.Items = append(queue.Items, item)
	queue.Length++
}

1.5 Pop()

// Pop 将该队列首元素弹出并返回
func (queue *SequentialQueue) Pop() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	item := queue.Items[0]
	queue.Items = queue.Items[1:]
	queue.Length--
	return item
}

1.6 Peek()

// Peek 获取该队列首元素但不出队
func (queue *SequentialQueue) Peek() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	return queue.Items[0]
}

1.7 Back()

// Back 获取该队列尾元素
func (queue *SequentialQueue) Back() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	return queue.Items[queue.Length-1]
}

2. 链式队列

1.1 结构定义

type Node struct {
	Data any
	Next *Node
}
type LinkedQueue struct {
	headNode *Node // 队首指针
	length   uint64
	tailNode *Node // 队尾指针
}

// NewLinkedQueue 初始化队列
func NewLinkedQueue() *LinkedQueue {
	return &LinkedQueue{}
}

1.2 IsEmpty()

// IsEmpty 判断队列是否为空
func (queue *LinkedQueue) IsEmpty() bool {
	return queue.headNode == nil
}

1.3 Push()

// Push 将元素添加到该队列末尾
func (queue *LinkedQueue) Push(data any) {
	node := &Node{Data: data}
	if queue.IsEmpty() {
		queue.headNode = node
		queue.tailNode = node
		return
	}
	queue.tailNode.Next = node
	queue.tailNode = node
}

1.4 Pop()

// Pop 将该队列首元素弹出并返回
func (queue *LinkedQueue) Pop() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	data := queue.headNode.Data
	queue.headNode = queue.headNode.Next
	return data
}

1.5 Peek()

// Peek 获取该队列首元素但不出队
func (queue *LinkedQueue) Peek() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	return queue.headNode.Data
}

1.6 Back()

// Back 获取该队列尾元素但不出队
func (queue *LinkedQueue) Back() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	return queue.tailNode.Data
}

1.7 Traverse()

// Traverse 遍历队列
func (queue *LinkedQueue) Traverse() {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return
	}
	currentNode := queue.headNode
	for currentNode.Next != nil {
		fmt.Printf("%v -> ", currentNode.Data)
		currentNode = currentNode.Next
	}
	fmt.Println(currentNode.Data)
}

3. 循环队列

如果通过数组实现顺序队列的话,有一个问题,就是随着队列元素的插入和删除,队尾指针和队头指针不断后移,从而导致队尾指针指向末尾无法继续插入数据,这时候有可能队列头部还是有剩余空间的。
这时候就用到循环队列,这里提供两种实现方法:

  1. 方案1:少使用一个位置
  2. 方案2:增加 Length 字段

方案1:少使用一个位置

1.1 结构定义
type LoopSeqQueue struct {
	Items []any
	Head  uint64 // 队首指针
	Tail  uint64 // 队尾指针
	Cap uint64 // 队列容量
}

func NewLoopSeqQueue(cap uint64) *LoopSeqQueue {
	return &LoopSeqQueue{
		Items: make([]any, cap+1), // 因为有一个位置要空着
		Head:  0,
		Tail:  0, // [0,cap-1]
		Cap: cap + 1, // 因为有一个位置要空着
	}
}

1.2 IsEmpty()
// IsEmpty 判断队列是否为空
func (queue *LoopSeqQueue) IsEmpty() bool {
	return queue.Head == queue.Tail
}
1.3 IsFull()
// IsFull 判断队列是否已满
func (queue *LoopSeqQueue) IsFull() bool {
	return (queue.Tail+1)%queue.Cap == queue.Head // 解释:尾指针的下一个是否是头指针
}
1.4 Push()
// Push 将元素添加到该队列末尾
func (queue *LoopSeqQueue) Push(data any) {
	if queue.IsFull() {
		fmt.Println("队列已满")
		return
	}
	queue.Items[queue.Tail] = data
	queue.Tail = (queue.Tail + 1) % queue.Cap // 尾指针后移
}

1.5 Pop()
// Pop 将该队列首元素弹出并返回
func (queue *LoopSeqQueue) Pop() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	data := queue.Items[queue.Head]
	queue.Head = (queue.Head + 1) % queue.Cap // 头指针后移
	return data
}
1.6 Peek()
// Peek 获取该队列首元素但不出队
func (queue *LoopSeqQueue) Peek() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	return queue.Items[queue.Head]
}
1.7 Back()
// Back 获取该队列尾元素但不出队
func (queue *LoopSeqQueue) Back() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	return queue.Items[(queue.Tail+queue.Cap-1)%queue.Cap] // 因为 tail 指向的那个少用的位置,所以不可以直接return items[tail]
}

方案2:增加 Length 字段

1.1 结构定义
type LoopSeqQueue struct {
	Items  []any
	Head   uint64 // 队首指针
	Tail   uint64 // 队尾指针
	Length uint64 // 队中元素个数
	Cap    uint64 // 队列容量
}

func NewLoopSeqQueue(cap uint64) *LoopSeqQueue {
	return &LoopSeqQueue{
		Items:  make([]any, cap),
		Head:   0,
		Tail:   0, // [0,cap-1]
		Length: 0,
		Cap:    cap,
	}
}
1.2 IsEmpty()
// IsEmpty 判断队列是否为空
func (queue *LoopSeqQueue) IsEmpty() bool {
	return queue.Length == 0
}
1.3 IsFull()
// IsFull 判断队列是否已满
func (queue *LoopSeqQueue) IsFull() bool {
	return queue.Length == queue.Cap
}
1.4 Push()
// Push 将元素添加到该队列末尾
func (queue *LoopSeqQueue) Push(data any) {
	// 略 ... 同方案一
	queue.Length++
}
1.5 Pop()
// Pop 将该队列首元素弹出并返回
func (queue *LoopSeqQueue) Pop() any {
	// 略 ... 同方案一
	queue.Length--
	return data
}
1.6 Peek() 和 Back() 和方案一一样

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1p11t0v32ihsm

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值