golang 队列

发布时间:2024-07-05 00:30:25

队列(Queue)是一种常见的数据结构,可以实现先进先出(FIFO)的操作。在编程中,队列通常用于解决需要按照特定顺序进行操作的问题。在Go语言中,队列的实现可以通过使用切片和链表来完成。

切片实现队列

切片是Go语言中常用的数据结构,它的长度和容量都可以动态调整。因此,我们可以使用切片来实现一个简单的队列。要创建一个队列,我们只需要定义一个切片变量和两个指针变量,分别指向队列的头部和尾部。

首先,我们定义一个Queue结构体,其中包含一个int类型的切片和两个int类型的指针变量front和rear:

type Queue struct {
    items []int
    front int
    rear  int
}

然后,我们可以定义一些与队列操作相关的方法,例如Enqueue、Dequeue、IsEmpty、Size等。下面是它们的具体实现:

func (q *Queue) Enqueue(item int) {
    q.items = append(q.items, item)
    q.rear++
}

func (q *Queue) Dequeue() int {
    if q.IsEmpty() {
        panic("queue is empty")
    }
    item := q.items[q.front]
    q.items = q.items[1:]
    q.rear--
    return item
}

func (q *Queue) IsEmpty() bool {
    return q.front == q.rear
}

func (q *Queue) Size() int {
    return len(q.items)
}

在Enqueue方法中,我们使用了切片的append函数将元素添加到队列的尾部,并更新rear指针。而在Dequeue方法中,我们通过切片的操作符[:]实现了将队列头部元素出队的功能,并同时更新front和rear指针。IsEmpty方法用于判断队列是否为空,Size方法返回队列的长度。

链表实现队列

除了使用切片,我们还可以使用链表来实现队列。链表是一种动态数据结构,不需要预先分配内存。在Go语言中,我们可以通过定义一个自定义的链表结构体和节点结构体来实现队列。

首先,我们定义一个Node结构体,其中包含一个int类型的数据和指向下一个节点的指针:

type Node struct {
    data int
    next *Node
}

type LinkedListQueue struct {
    front *Node
    rear  *Node
}

然后,我们可以定义一些与队列操作相关的方法,例如Enqueue、Dequeue、IsEmpty、Size等。下面是它们的具体实现:

func (q *LinkedListQueue) Enqueue(item int) {
    newNode := &Node{data: item, next: nil}
    if q.IsEmpty() {
        q.front = newNode
        q.rear = newNode
    } else {
        q.rear.next = newNode
        q.rear = newNode
    }
}

func (q *LinkedListQueue) Dequeue() int {
    if q.IsEmpty() {
        panic("queue is empty")
    }
    item := q.front.data
    q.front = q.front.next
    return item
}

func (q *LinkedListQueue) IsEmpty() bool {
    return q.front == nil
}

func (q *LinkedListQueue) Size() int {
    size := 0
    currentNode := q.front
    for currentNode != nil {
        size++
        currentNode = currentNode.next
    }
    return size
}

在Enqueue方法中,我们首先创建一个新的节点,并将其加入到队列的尾部。如果队列为空,则同时更新front和rear指针;否则,只需要更新rear指针。而在Dequeue方法中,我们直接将头部节点出队,并更新front指针。IsEmpty方法用于判断队列是否为空,Size方法返回队列的长度。

使用队列解决问题

队列在实际开发中经常用于解决一些问题,例如广度优先搜索(BFS)、任务调度等。下面以广度优先搜索为例,演示如何在Go语言中使用队列解决问题。

假设我们需要求一张图中两个节点之间的最短路径。使用DFS(深度优先搜索)算法可能存在效率较低的问题,而使用BFS算法则可以较快地找到最短路径。

首先,我们定义一个图结构体,包含一个int类型的二维切片作为邻接矩阵,并定义一个Queue队列:

type Graph struct {
    matrix [][]int
}

type Queue struct {
    items []int
}

然后,我们可以使用BFS算法求出两个节点之间的最短路径。下面是具体的实现代码:

func (g *Graph) BFS(start int, end int) []int {
    queue := Queue{}
    visited := make([]bool, len(g.matrix))
    prev := make([]int, len(g.matrix))
    distance := make([]int, len(g.matrix))

    for i := range prev {
        prev[i] = -1
    }

    queue.Enqueue(start)
    visited[start] = true

    for !queue.IsEmpty() {
        vertex := queue.Dequeue()
        
        if vertex == end {
            break
        }

        for i := 0; i < len(g.matrix); i++ {
            if g.matrix[vertex][i] != 0 && !visited[i] {
                queue.Enqueue(i)
                visited[i] = true
                prev[i] = vertex
                distance[i] = distance[vertex] + 1
            }
        }
    }
    
    path := []int{end}
    p := prev[end]
    for p != -1 {
        path = append([]int{p}, path...)
        p = prev[p]
    }
    
    return path
}

在BFS方法中,我们首先创建一个Queue队列,并定义一个布尔型的visited切片用于记录节点是否被访问过,以及一个prev切片用于记录每个节点的前驱节点和距离。

然后,我们将起始节点加入到队列中,并将其设置为已访问。接下来,我们开始进行广度优先搜索,直到队列为空。在每一轮搜索中,我们取出队列的头部节点,并遍历该节点的邻居节点。如果邻居节点尚未被访问,则将其加入到队列中,并更新prev和distance切片。

最后,我们通过回溯prev切片构建最短路径,并返回结果。

通过以上的方法,我们可以用队列解决一些基本的数据结构问题,例如实现一个简单的队列、根据BFS算法求解图中最短路径等。队列作为一种重要的数据结构,在编程中有着广泛的应用。

相关推荐