数据结构|队列

完成阅读您将会了解队列的:

  1. 概念
  2. 构建方法
  3. 基本操作
  4. C++实现
  5. Rust实现

1. 概念

队列Queue)是一种抽象数据类型,遵循先进先出First-In-First-Out, FIFO)原则,双端开放的线性表,如图1[1]。队列可以辅助完成广度优先搜索Breadth First Search)算法的实现。此外,队列有一个常用的变体,优先队列Priority Queue)。优先队列属于二叉堆Binary Heap)的一个应用,具体内容请参考数据结构堆

图1:队列

图1:队列

2. 构建方法

数组双链表都可以作为构建队列的基础容器。用数组构建队列时可以采用循环队列Circular Queue),提高空间利用率。

3. 基本操作

操作 描述 时间复杂度 空间复杂度
PUSH(value) 队尾入队 \(\Theta(1)\) \(\Theta(1)\)
POP() 队头出队 \(\Theta(1)\) \(\Theta(1)\)

4. C++实现

template <class T> struct Node {
  T val;
  Node *before, *after;
  Node(auto val) : val(val), before(nullptr), after(nullptr) {}
  Node() : Node(0) {}
};

template <class T> class Queue {
  Node<T> *head, *tail;
  size_t len;

public:
  Queue() : head(nullptr), tail(nullptr), len(0) {}
  ~Queue() {
    while (head) {
      auto garbage = head;
      head = head->after;
      delete garbage;
    }
  }
  constexpr auto front() const { return head->val; }
  inline void pop() noexcept {
    if (head) {
      auto garbage = head;
      head = head->after;
      delete garbage;
      garbage = nullptr;
      --len;
    }
  }
  inline void push(auto val) noexcept {
    auto new_node = new Node(val);
    head ? (new_node->before = tail, tail->after = new_node) : head = new_node;
    tail = new_node;
    ++len;
  }
  constexpr auto empty() const noexcept { return len == 0; }
  constexpr auto size() const noexcept { return len; } 
};

此外,C++标准库提供了队列queue与双端队列deque直接使用。

5. Rust实现

impl<T> Queue<T> {
    #[inline]
    pub fn new() -> Self { Self { head: None, tail: None, size: 0 } }
    #[inline]
    pub fn front(&self) -> Option<&T> {
        self.head.as_ref().map(|node| unsafe { &node.as_ref().val })
    }
    #[inline]
    fn pop(&mut self) {
        if let Some(node) = self.head.take() {
            unsafe {
                let node = Box::from_raw(node.as_ptr());
                self.head = node.after;
                match self.head {
                    None => self.tail = None,
                    Some(head) => (*head.as_ptr()).before = None,
                }
            }
            self.size -= 1;
        }
    }
    #[inline]
    fn push(&mut self, val: T) {
        let node = Some(Box::leak(Box::new(Node { after: None, before: self.tail, val })).into());
        match self.tail {
            None => self.head = node,
            Some(tail) => unsafe { (*tail.as_ptr()).after = node },
        }
        self.tail = node;
        self.size += 1;
    }
    #[inline]
    pub fn empty(&self) -> bool { self.size == 0 }
    #[inline]
    pub fn len(&self) -> usize { self.size }
}

unsafe impl<#[may_dangle] T>Drop for Queue<T> {
    fn drop(&mut self) {
        struct DropGuard<'a, T>(&'a mut Queue<T>);
        impl<'a,T>Drop for DropGuard<'a,T>{
            #[inline]
            fn drop(&mut self){ while !self.0.empty(){} }
        }
        while let Some(node)=self.head{
            let guard=DropGuard(self);
            drop(node);
            mem::forget(guard);
            self.head=unsafe{(*node.as_ptr()).after};
        }
    }
}

struct Queue<T> {
    head: Option<NonNull<Node<T>>>,
    tail: Option<NonNull<Node<T>>>,
    size: usize,
}

struct Node<T> {
    val: T,
    before: Option<NonNull<Node<T>>>,
    after: Option<NonNull<Node<T>>>,
}

此外,Rust标准库提供了双端队列VecDeque直接使用。

6. 自我测试

伪代码实践
N/A

LeetCode选荐

  1. Number of Recent Calls
  2. Design Circular Queue
  3. Design Circular Deque
  4. Sliding Window Maximum
  5. Shortest Subarray with Sum at Least K

测试参考解答

让每一天足够精致,期待与您的再次相遇! ^_^


  1. 图片引自Wikipedia,在此鸣谢。 ↩︎

posted @ 2021-07-06 19:31  我的名字被占用  阅读(81)  评论(0)    收藏  举报