stack and queue

·data-structure-and-algorithm
#data-structure

栈(Stack)

什么是栈?

  • 逻辑模型:一种后进先出(LIFO,Last In First Out)的线性结构

  • 核心操作:

    • Push:将元素压入栈顶

    • Pop:将栈顶元素弹出

    • Top / Peek:访问栈顶元素但不删除

    • Empty:判断栈是否为空

    • Size:获取当前栈中元素个数

应用场景

  • 函数调用栈(保存局部变量、返回地址)

  • 表达式求值(中缀转后缀、算术运算)

  • 括号匹配(编译原理)

  • 深度优先搜索(DFS)

C++ 中的栈

STL 实现:std::stack
# include <iostream>
# include <stack>

int main()
{
    std::stack<int> st;            // 底层默认是 deque<int>
    st.push(10);                   // 压入元素
    st.push(20);
    std::cout << "栈顶元素: " << st.top() << "\n";  // 20
    st.pop();                      // 弹出 20
    std::cout << "弹出后栈顶: " << st.top() << "\n"; // 10
    std::cout << "当前大小: " << st.size() << "\n"; // 1
    std::cout << "是否为空: " << std::boolalpha << st.empty() << "\n"; // false
    return 0;
}

优点:调用方便,功能齐全,底层容器可自定义(dequevectorlist

缺点:无法随机访问中间元素,只能操作栈顶

自定义实现

基于动态数组(vector

template<typename T>
class ArrayStack
{
private:
    std::vector<T> data;
public:
    void push(const T& x) { data.push_back(x); }
    void pop() { if (!data.empty()) data.pop_back(); }
    T& top() { return data.back(); }
    bool empty() const { return data.empty(); }
    size_t size() const { return data.size(); }
};

基于链表

template<typename T>
struct Node {
    T val;
    Node* next;
    Node(const T& v, Node* n = nullptr) : val(v), next(n) {}
};

template<typename T>
class LinkedStack {
private:
    Node<T>* head = nullptr;
    size_t cnt = 0;
public:
    void push(const T& x) {
        head = new Node<T>(x, head);
        ++cnt;
    }
    void pop() {
        if (!head) return;
        Node<T>* tmp = head;
        head = head->next;
        delete tmp;
        --cnt;
    }
    T& top() { return head->val; }
    bool empty() const { return head == nullptr; }
    size_t size() const { return cnt; }
    ~LinkedStack() {
        while (head) pop();
    }
};

Go 中的栈

Go 标准库没有专门的 stack 类型,但我们可以基于 slicecontainer/list(go 标准库提供的双向链表)来实现

基于 slice
package main

import "fmt"

type Stack[T any] struct {
    data []T
}

func (s *Stack[T]) Push(v T) {
    s.data = append(s.data, v)
}

func (s *Stack[T]) Pop() (T, bool) {
    if len(s.data) == 0 {
        var zero T

        return zero, false
    }

    idx := len(s.data) - 1
    v := s.data[idx]

    s.data = s.data[:idx]

    return v, true
}

func (s *Stack[T]) Top() (T, bool) {
    if len(s.data) == 0 {
        var zero T

        return zero, false
    }

    return s.data[len(s.data)-1], true
}

func (s *Stack[T]) Empty() bool {
    return len(s.data) == 0
}

func (s *Stack[T]) Size() int {
    return len(s.data)
}

func main() {
    st := Stack[int]{}
    st.Push(100)
    st.Push(200)

    if top, ok := st.Top(); ok {
        fmt.Println("栈顶:", top) // 200
    }

    if val, ok := st.Pop(); ok {
        fmt.Println("弹出:", val) // 200
    }

    fmt.Println("当前大小:", st.Size())
}
基于 container/list
package main

import (
    "container/list"
    "fmt"
)

type StackList[T any] struct {
    l *list.List
}

func NewStackList[T any]() *StackList[T] {
    return &StackList[T]{l: list.New()}
}

func (s *StackList[T]) Push(v T) {
    s.l.PushBack(v)
}

func (s *StackList[T]) Pop() (T, bool) {
    e := s.l.Back()

    if e == nil {
        var zero T

        return zero, false
    }

    s.l.Remove(e)

    return e.Value.(T), true
}

func (s *StackList[T]) Top() (T, bool) {
    e := s.l.Back()

    if e == nil {
        var zero T

        return zero, false
    }

    return e.Value.(T), true
}

func (s *StackList[T]) Empty() bool {
    return s.l.Len() == 0
}

func (s *StackList[T]) Size() int {
    return s.l.Len()
}

func main() {
    st := NewStackList[int]()
    st.Push(1)
    st.Push(2)

    if v, ok := st.Pop(); ok {
        fmt.Println("Pop:", v)
    }

    fmt.Println("Size:", st.Size())
}

队列(Queue)

什么是队列?

  • 逻辑模型:一种先进先出(FIFO,First In First Out)的线性结构

  • 核心操作:

    • Enqueue(入队):在队尾插入元素

    • Dequeue(出队):从队头移除元素

    • Front / Peek:访问队头元素

    • Empty:判断队列是否为空

    • Size:获取元素个数

应用场景

  • 广度优先搜索(BFS)

  • 任务调度

  • 缓冲区(如生产者–消费者模型)

  • 消息队列

C++ 中的队列

STL 实现:std::queue
# include <iostream>
# include <queue>

int main()
{
    std::queue<std::string> q;  // 底层同样默认 deque
    q.push("A");
    q.push("B");
    std::cout << "队头: " << q.front() << "\n";  // A
    q.pop();
    std::cout << "出队后队头: " << q.front() << "\n"; // B
    std::cout << "大小: " << q.size() << "\n";       // 1
    std::cout << "是否为空: " << std::boolalpha << q.empty() << "\n"; // false
    return 0;
}
自定义实现

基于循环数组

template<typename T>
class CircularQueue {
private:
    std::vector<T> buf;
    size_t head = 0, tail = 0, cnt = 0;
public:
    CircularQueue(size_t capacity) : buf(capacity) {}
    bool enqueue(const T& x) {
        if (cnt == buf.size()) return false; 
        buf[tail] = x;
        tail = (tail + 1) % buf.size();
        ++cnt;
        return true;
    }
    bool dequeue() {
        if (cnt == 0) return false;
        head = (head + 1) % buf.size();
        --cnt;
        return true;
    }
    T& front() { return buf[head]; }
    bool empty() const { return cnt == 0; }
    size_t size() const { return cnt; }
};

基于链表

template<typename T>
struct QNode {
    T val; QNode* next;
    QNode(const T& v) : val(v), next(nullptr) {}
};

template<typename T>
class LinkedQueue {
private:
    QNode<T>* head = nullptr;
    QNode<T>* tail = nullptr;
    size_t cnt = 0;
public:
    void enqueue(const T& x) {
        auto node = new QNode<T>(x);
        if (!tail) head = node;
        else tail->next = node;
        tail = node;
        ++cnt;
    }
    void dequeue() {
        if (!head) return;
        auto tmp = head;
        head = head->next;
        if (!head) tail = nullptr;
        delete tmp;
        --cnt;
    }
    T& front() { return head->val; }
    bool empty() const { return cnt == 0; }
    size_t size() const { return cnt; }
    ~LinkedQueue() { while (head) dequeue(); }
};

Go 中的队列

同样可以用 slicecontainer/list 来实现

基于 slice
package main

import "fmt"

type Queue[T any] struct {
    data []T
}

func (q *Queue[T]) Enqueue(v T) {
    q.data = append(q.data, v)
}

func (q *Queue[T]) Dequeue() (T, bool) {
    if len(q.data) == 0 {
        var zero T

        return zero, false
    }

    v := q.data[0]
    q.data = q.data[1:]

    return v, true
}

func (q *Queue[T]) Front() (T, bool) {
    if len(q.data) == 0 {
        var zero T

        return zero, false
    }

    return q.data[0], true
}

func (q *Queue[T]) Empty() bool {
    return len(q.data) == 0
}

func (q *Queue[T]) Size() int {
    return len(q.data)
}

func main() {
    q := Queue[string]{}
    q.Enqueue("task1")
    q.Enqueue("task2")

    if front, ok := q.Front(); ok {
        fmt.Println("队头:", front) // task1
    }

    if v, ok := q.Dequeue(); ok {
        fmt.Println("出队:", v)     // task1
    }

    fmt.Println("剩余大小:", q.Size())
}
基于 container/list
package main

import (
    "container/list"
    "fmt"
)

type QueueList[T any] struct {
    l *list.List
}

func NewQueueList[T any]() *QueueList[T] {
    return &QueueList[T]{l: list.New()}
}

func (q *QueueList[T]) Enqueue(v T) {
    q.l.PushBack(v)
}

func (q *QueueList[T]) Dequeue() (T, bool) {
    e := q.l.Front()

    if e == nil {
        var zero T

        return zero, false
    }

    q.l.Remove(e)
    return e.Value.(T), true
}

func (q *QueueList[T]) Front() (T, bool) {
    e := q.l.Front()

    if e == nil {
        var zero T

        return zero, false
    }

    return e.Value.(T), true
}

func (q *QueueList[T]) Empty() bool {
    return q.l.Len() == 0
}

func (q *QueueList[T]) Size() int {
    return q.l.Len()
}

func main() {
    q := NewQueueList[int]()
    q.Enqueue(5)
    q.Enqueue(6)
    if v, ok := q.Dequeue(); ok {
        fmt.Println("Dequeue:", v)
    }
    fmt.Println("Size:", q.Size())
}

小结

  • 栈:

    • 后进先出,适合函数调用、表达式处理、DFS 等场景

    • C++ 有 std::stack

    • Go 可用 slicecontainer/list

  • 队列:

    • 先进先出,适合 BFS、任务调度、生产者-消费者等

    • C++ 有 std::queue

    • Go 同样可基于 slicecontainer/list 实现