个人技术分享

队列(Queue)是一种先进先出(First In First Out, FIFO)的线性数据结构,它有两个主要操作:入队(enqueue)和出队(dequeue)。队列通常用于存储按顺序处理的数据,比如任务调度、打印任务管理等场景。

队列的主要特点和操作如下:

  1. 入队(Enqueue):在队列的尾部添加一个元素。
  2. 出队(Dequeue):从队列的头部移除一个元素。
  3. 队首(Front)或 Peek:查看队列头部的元素,但不移除它。
  4. 队尾(Rear):查看队列尾部的元素。
  5. 是否为空(IsEmpty):检查队列是否为空。
  6. 大小(Size):获取队列中元素的数量。

在Go语言中,队列没有内置的数据结构,但可以使用切片(slice)、链表(list包)或其他自定义数据结构来实现。以下是使用切片实现队列的基本操作:

package main

import "fmt"

// 使用切片定义队列类型
type Queue []interface{}

// 入队操作
func (q *Queue) Enqueue(value interface{}) {
	*q = append(*q, value)
}

// 出队操作
func (q *Queue) Dequeue() (interface{}, bool) {
	if q.IsEmpty() {
		return nil, false
	}
	value := (*q)[0]  // 获取队列头部元素
	*q = (*q)[1:]     // 移除队列头部元素
	return value, true
}

// 查看队首元素
func (q *Queue) Front() (interface{}, bool) {
	if q.IsEmpty() {
		return nil, false
	}
	return (*q)[0], true
}

// 检查队列是否为空
func (q *Queue) IsEmpty() bool {
	return len(*q) == 0
}

// 获取队列大小
func (q *Queue) Size() int {
	return len(*q)
}

func main() {
	// 创建队列
	var q Queue

	// 入队操作
	q.Enqueue(1)
	q.Enqueue(2)
	q.Enqueue(3)

	// 出队操作
	value, ok := q.Dequeue()
	if ok {
		fmt.Println("Dequeued:", value)
	}

	// 查看队首元素
	front, ok := q.Front()
	if ok {
		fmt.Println("Front item:", front)
	}

	// 检查队列是否为空
	fmt.Println("Is queue empty?", q.IsEmpty())

	// 获取队列大小
	fmt.Println("Queue size:", q.Size())
}

在这个例子中,我们定义了一个Queue类型,它是一个interface{}类型的切片。这允许我们将任何类型的元素添加到队列中。我们实现了EnqueueDequeue方法来添加和移除元素,以及FrontIsEmptySize方法来查看队列的状态。

【*q的使用】
在Go语言中,使用*q的原因与Go的值传递机制有关。Go中的所有函数参数都是值传递,这意味着它们会复制实参到函数内部作为形参。 如果你希望在函数内部修改原始数据而不是它的副本,你需要使用指针。指针允许你直接访问和修改原始数据。

在这段代码中:

func (q *Queue) Enqueue(value interface{}) {
    *q = append(*q, value)
}

q是指向Queue类型的指针。这里Queue本质上是一个切片。当你想要修改这个切片(即队列)本身(比如添加或删除元素),而不仅仅是修改它的内容,你需要操作切片的指针。这样,任何对切片的修改都会反映在原始切片上,而不仅仅是它的一个本地副本。

  • *q表示对q指针指向的值的解引用,让我们可以直接访问和修改它。
  • append(*q, value)是将新元素value添加到*q指向的切片(即队列)中。append函数可能会改变切片的长度和容量,有时甚至会返回一个全新的切片头部指针,因此需要用*q =来确保q指针指向的切片是更新后的切片。

简而言之,使用*q是为了确保你在Enqueue方法中对队列所做的修改(如添加元素)会直接影响到原始的队列,而不仅仅是它的一个副本。这是通过直接操作队列的指针来实现的。