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

2023-04-16 15:41:07 浏览数 (1)

队列

1. 顺序队列

1.1 结构定义

代码语言:javascript复制
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()

代码语言:javascript复制
// IsEmpty 判断队列是否为空
func (queue *SequentialQueue) IsEmpty() bool {
	return queue.Length == 0
}

1.3 IsFull()

代码语言:javascript复制
// IsFull 判断队列是否为满
func (queue *SequentialQueue) IsFull() bool {
	return queue.Length == queue.Cap
}

1.4 Push()

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

1.5 Pop()

代码语言:javascript复制
// 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()

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

1.7 Back()

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

2. 链式队列

1.1 结构定义

代码语言:javascript复制
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()

代码语言:javascript复制
// IsEmpty 判断队列是否为空
func (queue *LinkedQueue) IsEmpty() bool {
	return queue.headNode == nil
}

1.3 Push()

代码语言:javascript复制
// 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()

代码语言:javascript复制
// 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()

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

1.6 Back()

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

1.7 Traverse()

代码语言:javascript复制
// 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 结构定义
代码语言:javascript复制
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()
代码语言:javascript复制
// IsEmpty 判断队列是否为空
func (queue *LoopSeqQueue) IsEmpty() bool {
	return queue.Head == queue.Tail
}
1.3 IsFull()
代码语言:javascript复制
// IsFull 判断队列是否已满
func (queue *LoopSeqQueue) IsFull() bool {
	return (queue.Tail 1)%queue.Cap == queue.Head // 解释:尾指针的下一个是否是头指针
}
1.4 Push()
代码语言:javascript复制
// 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()
代码语言:javascript复制
// 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()
代码语言:javascript复制
// Peek 获取该队列首元素但不出队
func (queue *LoopSeqQueue) Peek() any {
	if queue.IsEmpty() {
		fmt.Println("空队列")
		return nil
	}
	return queue.Items[queue.Head]
}
1.7 Back()
代码语言:javascript复制
// 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 结构定义
代码语言:javascript复制
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()
代码语言:javascript复制
// IsEmpty 判断队列是否为空
func (queue *LoopSeqQueue) IsEmpty() bool {
	return queue.Length == 0
}
1.3 IsFull()
代码语言:javascript复制
// IsFull 判断队列是否已满
func (queue *LoopSeqQueue) IsFull() bool {
	return queue.Length == queue.Cap
}
1.4 Push()
代码语言:javascript复制
// Push 将元素添加到该队列末尾
func (queue *LoopSeqQueue) Push(data any) {
	// 略 ... 同方案一
	queue.Length  
}
1.5 Pop()
代码语言:javascript复制
// Pop 将该队列首元素弹出并返回
func (queue *LoopSeqQueue) Pop() any {
	// 略 ... 同方案一
	queue.Length--
	return data
}
1.6 Peek() 和 Back() 和方案一一样

0 人点赞