目录

队列 Queue

Algorithm Notes

Mark Chen | 10 May 2021

你使用哪种语言?我们会根据你选择的语言显示对应的代码示例

Python
Java

前置条件

在学习这个知识点前,你应该先学习……

队列

队列 (Queue) 是一种用于收集数据的线性数据结构,主要有两个操作:

因为在这个数据结构中,最先放入的元素会被最先取出来,和日常生活中的排队情境一样,所以这个数据结构被称作队列

Fifo_queue

编程实现

0 - 一个基于 list 的朴素实现

在 Python 与 Java 中,语言的 list 都提供了删除特定元素和在列表末尾添加元素的方法。 所以一种最朴素的实现可以直接使用语言的 list 来完成。

	
class Queue:
	def __init__(self):
		self.data = list()

	def push(self, element):
		self.data.append(element)
	
	def pop(self):
		if len(self.data) > 0: return self.data.pop(0)
		else: raise Exception("Cannot pop from an Empty Queue")
	
	
	
import java.util.*;

class Queue{
	private ArrayList<Integer> arr = new ArrayList<>();

	public void push(int element){
		this.arr.add(element);
	}
	
	public int pop(){
		if (this.arr.size() > 0){
			int result = this.arr.get(0);
			this.arr.remove(0);
			return result;
		}
		else{
			return -1;
		}
	}
}
	

这种实现方法虽然可以 work,但是当你考虑时间复杂度的时候,你会发现这个实现实际上是非常低效的 - 每次从队列中取出一个元素的时候,你都要从队列中拿出第 0 项,同时将 1 ~ n 的所有元素依次向前挪动一格。 这说明每次从队列中取出元素的时间复杂度是 $O(n)$。

那么有没有可能换一种实现数据结构的方法,从而达到放取都是 $O(1)$ 的时间复杂度的效果呢?

下面我们来看看如何使用刚刚学习的 链表 数据结构来提高 Queue 的效率

1 - 更加高效的队列(链表)

虽然访问链表中间的第 $n$ 个元素需要 $O(n)$ 的时间复杂度,我们可以非常方便的在链表的首尾做对元素进行增删的操作。每次在链表末尾增添一个元素只需要 $O(1)$ 的时间复杂度;同时,删除链表头部的元素也只需要 $O(1)$ 的时间复杂度。通过这两个特性,我们可以让队列做到进出都只需要 $O(1)$ 的时间复杂度。

	
class LinkedListNode:
    def __init__(self, val: int) -> None:
        self.next = None
        self.val = val

class Queue:
    def __init__(self) -> None:
        self.head = None
        self.tail = None
        self.size = 0
    
    def push(self, val: int) -> None:
        self.size += 1
        new_node = LinkedListNode(val)
        if self.head == None:
            self.head = new_node
            self.tail = new_node
        else:
            self.tail.next = new_node
            self.tail = self.tail.next
    
    def pop(self) -> int:
        self.size -= 1
        val = self.head.val
        self.head = self.head.next
        return val
    
    def size(self) -> int:
        return self.size
    
    def peek(self) -> int:
        return self.head.val
    
    def __str__(self) -> str:
        ptr = self.head
        string = "HEAD -> "
        while ptr.next != None:
            string += str(ptr.val) + " -> "
            ptr = ptr.next
        string += str(ptr.val) + " -> "
        string += "TAIL"
        return string
    
    
Not Implemented yet, see Python Version
	

2 - 更加高效的队列(循环数组)

除了链表以外,我们还可以用循环数组来实现队列。

b0da01935156ce1789cbf366607545d

	
class Queue:
    def __init__(self, max_capacity: int) -> None:
        self.arr = [0] * max_capacity
        self.max_len = max_capacity
        self.start = 0
        self.end = 0
    
    def size(self) -> int:
        return self.end - self.start
    
    def push(self, item: int) -> None:
        self.end += 1
        actual_index = (self.end - 1) % self.max_len
        self.arr[actual_index] = item
    
    def pop(self) -> None:
        actual_index = self.start % self.max_len
        self.start += 1
        return self.arr[actual_index]
    
    def peek(self) -> int:
        return self.arr[self.start % self.max_len]
    
    def __str__(self) -> str:
        string = "[ "
        for index, num in enumerate(self.arr):
            string += str(num)
            if index == self.start % self.max_len:
                string += "(START)"
            if index == self.end % self.max_len:
                string += "(END)"
            string += " | "
        string += " ]"
        return string
	
	
Not Implemented Yet, see Python Version
	

练习


评论区