【C++STL】容器适配器——stack,queue,priority_queue用法详解

目录

一.stack(栈)

1.1.构造函数

1.2.常用操作

二.queue(队列)

2.1.构造函数

2.2.常用操作

三.priority_queue(优先级队列)

3.1.构造函数

3.3.常用操作


一.stack(栈)

  1. 栈的本质:容器适配器

首先理解关键点:C++中的stack不是独立的容器,而是"容器适配器"。它不自己管理内存,而是包装一个已有的底层容器(默认是deque),为其添加栈的接口(LIFO操作)。

  1. 为什么需要基于已有容器构造?

场景一:快速构建已有数据的栈视图

假设你有一个现成的数据集合,原本用vector或list存储,现在需要以"后进先出"的方式处理。这时你可以:

  • 选择一:写循环,逐个push进栈 → 需要额外代码,且效率较低

  • 选择二:直接用已有容器构造栈 → 简洁高效,底层直接复用已有数据

场景二:数据处理的阶段转换

程序中常有这种模式:

  1. 收集阶段:用vector等随机访问容器收集数据

  2. 处理阶段:需要按特定顺序(如逆序)处理

    这时将已有容器构造为栈,就是自然的转换桥梁。

场景三:复用已有容器特性

不同底层容器有不同特性:

  • deque(默认):两端增删快,内存非连续

  • vector:内存连续,缓存友好,但只能在末端增删

  • list:任何位置增删快,但内存不连续

当你的程序已经使用了特定容器,并想基于它实现栈操作时,这个构造函数让你能保持原有容器类型的同时获得栈接口

官网:cplusplus.com/reference/stack/stack/?kw=stack

1.1.构造函数

作为一个容器适配器,它只有一种构造函数

复制代码
explicit stack(const container_type& ctnr = container_type());

这个构造函数有两种用法:

  1. 默认构造:创建空栈

  2. 使用已有容器构造:复制容器内容作为栈的初始内容

cpp 复制代码
#include <iostream>
#include <stack>
#include <vector>
#include <deque>

int main() {
    // 1. 默认构造 - 空栈
    std::stack<int> s1;  // 使用默认的deque作为底层容器
    std::cout << "s1 size: " << s1.size() << std::endl;  // 输出: 0
    
    // 2. 使用vector作为底层容器(指定容器类型)
    std::stack<int, std::vector<int>> s2;
    std::cout << "s2 size: " << s2.size() << std::endl;  // 输出: 0
    
    // 3. 使用已有容器初始化(复制容器内容)
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::stack<int, std::vector<int>> s3(vec);  // 使用vec初始化栈
    
    std::cout << "s3 size: " << s3.size() << std::endl;  // 输出: 5
    
    // 查看栈顶元素(应该是vec的最后一个元素)
    std::cout << "s3 top: " << s3.top() << std::endl;  // 输出: 5
    
    // 4. 使用deque初始化(stack默认容器)
    std::deque<int> deq = {10, 20, 30};
    std::stack<int> s4(deq);  // 使用deque初始化栈
    
    std::cout << "s4 top: " << s4.top() << std::endl;  // 输出: 30
    
    // 5. 弹出元素验证栈的顺序(LIFO)
    std::cout << "\nPopping s3 elements: ";
    while (!s3.empty()) {
        std::cout << s3.top() << " ";
        s3.pop();
    }
    // 输出: 5 4 3 2 1 (后进先出)
    
    return 0;
}

  1. explicit 关键字的作用
cpp 复制代码
// 错误示例:不能隐式转换
std::vector<int> vec = {1, 2, 3};
// std::stack<int> s = vec;  // 错误!不能隐式转换

// 正确示例:必须显式调用构造函数
std::stack<int, std::vector<int>> s(vec);  // 正确

2.底层容器类型

默认使用 deque<T>

可以指定其他容器,但必须满足四个基本操作就可以作为stack的底层容器:

  1. push_back() - 在末尾添加元素(对应stack的push)

  2. pop_back() - 从末尾删除元素(对应stack的pop)

  3. back() - 访问末尾元素(对应stack的top)

  4. empty()size() - 容量查询

我们再看一个例子

cpp 复制代码
#include <iostream>
#include <stack>
#include <list>

int main() {
    // 使用list作为底层容器初始化栈
    std::list<std::string> tasks = {"Task A", "Task B", "Task C"};
    std::stack<std::string, std::list<std::string>> taskStack(tasks);
    
    std::cout << "Processing tasks (LIFO):\n";
    while (!taskStack.empty()) {
        std::cout << "Processing: " << taskStack.top() << std::endl;
        taskStack.pop();
    }
    // 输出:
    // Processing: Task C
    // Processing: Task B
    // Processing: Task A
    
    return 0;
}

1.2.常用操作

作为容器适配器,我们的stack也是提供了一些栈独有的数据结构。

empty

  • 作用:检查栈是否为空
  • 返回:bool 类型,栈为空时返回 true,否则返回 false
cpp 复制代码
#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;
    
    // 检查空栈
    if (myStack.empty()) {
        std::cout << "栈是空的" << std::endl;  // 会执行这里
    } else {
        std::cout << "栈不是空的" << std::endl;
    }
    
    // 添加元素后检查
    myStack.push(10);
    
    if (!myStack.empty()) {
        std::cout << "现在栈不是空的" << std::endl;  // 会执行这里
    }
    
    // 清空栈后检查
    myStack.pop();
    
    if (myStack.empty()) {
        std::cout << "栈又变成空的了" << std::endl;  // 会执行这里
    }
    
    return 0;
}

size

  • 作用:返回栈中当前元素的个数
  • 返回:无符号整型,表示元素数量
cpp 复制代码
#include <iostream>
#include <stack>

int main() 
{
    std::stack<std::string> nameStack;
    
    // 初始大小
    std::cout << "初始大小: " << nameStack.size() << std::endl;  // 输出: 0
    
    // 添加元素
    nameStack.push("Alice");
    nameStack.push("Bob");
    nameStack.push("Charlie");
    
    std::cout << "添加3个元素后的大小: " << nameStack.size() << std::endl;  // 输出: 3
    
    // 移除元素
    nameStack.pop();
    std::cout << "移除1个元素后的大小: " << nameStack.size() << std::endl;  // 输出: 2
    
    // 继续添加
    nameStack.push("David");
    nameStack.push("Eve");
    
    std::cout << "再添加2个元素后的大小: " << nameStack.size() << std::endl;  // 输出: 4
    
    return 0;
}

top

  • 作用:访问栈顶元素(下一个要处理的元素),但是不会移动栈顶元素
  • 返回栈顶元素的引用(可修改) ,但不删除该元素。
  • 注意:不会移除元素,只是查看。如果栈为空调用此函数是未定义行为
cpp 复制代码
#include <iostream>
#include <stack>

int main() {
    std::stack<int> numbers;
    
    // 示例1: 基本使用
    numbers.push(10);
    numbers.push(20);
    numbers.push(30);
    
    std::cout << "栈顶元素: " << numbers.top() << std::endl;  // 输出: 30
    
    // 示例2: 查看但不删除
    std::cout << "再次查看栈顶: " << numbers.top() << std::endl;  // 输出: 30
    std::cout << "栈大小仍然是: " << numbers.size() << std::endl;  // 输出: 3
    
    // 示例3: 修改栈顶元素
    numbers.top() = 99;  // 修改栈顶元素的值
    std::cout << "修改后栈顶元素: " << numbers.top() << std::endl;  // 输出: 99
    
    return 0;
}

push

  • 作用:插入元素到栈顶,成为新的栈顶
  • 参数:要插入的元素值(会复制或移动)
cpp 复制代码
#include <iostream>
#include <stack>

int main() {
    std::stack<int> numbers;
    
    // 基本使用
    std::cout << "初始栈大小: " << numbers.size() << std::endl;
    
    numbers.push(10);
    std::cout << "push(10)后,栈顶: " << numbers.top() << std::endl;
    std::cout << "栈大小: " << numbers.size() << std::endl;
    
    numbers.push(20);
    std::cout << "push(20)后,栈顶: " << numbers.top() << std::endl;
    std::cout << "栈大小: " << numbers.size() << std::endl;
    
    numbers.push(30);
    std::cout << "push(30)后,栈顶: " << numbers.top() << std::endl;
    std::cout << "栈大小: " << numbers.size() << std::endl;
    
    return 0;
}

emplace

  • 作用:在栈顶原地构造元素
  • 用法:相比 push 更高效,直接在栈顶位置构造对象,避免临时对象的创建和拷贝
  • 参数:构造元素所需的参数列表
cpp 复制代码
#include <iostream>
#include <stack>
#include <string>

class Person {
public:
    std::string name;
    int age;
    
    // 构造函数
    Person(std::string n, int a) : name(n), age(a) {
        std::cout << "Person对象被构造: " << name << std::endl;
    }
    
    // 拷贝构造函数
    Person(const Person& other) : name(other.name), age(other.age) {
        std::cout << "Person对象被拷贝: " << name << std::endl;
    }
    
    // 移动构造函数
    Person(Person&& other) noexcept : name(std::move(other.name)), age(other.age) {
        std::cout << "Person对象被移动: " << name << std::endl;
    }
};

int main() {
    std::stack<Person> peopleStack;
    
    std::cout << "=== 使用 push() 创建临时对象 ===" << std::endl;
    // push会创建临时对象,然后拷贝或移动到栈中
    peopleStack.push(Person("Alice", 25));  
    // 输出:
    // Person对象被构造: Alice (临时对象)
    // Person对象被移动: Alice (移动到栈中)
    
    std::cout << "\n=== 使用 emplace() 直接构造 ===" << std::endl;
    // emplace直接在栈中构造对象,避免临时对象
    peopleStack.emplace("Bob", 30);  
    // 输出:
    // Person对象被构造: Bob (直接在栈中构造)
    
    std::cout << "\n=== 访问栈顶 ===" << std::endl;
    std::cout << "栈顶人员: " << peopleStack.top().name << std::endl;  // Bob
    
    // 更多emplace示例
    std::stack<std::pair<int, std::string>> pairStack;
    
    // 使用push需要创建pair对象
    pairStack.push(std::pair<int, std::string>(1, "Hello"));
    
    // 使用emplace更简洁高效
    pairStack.emplace(2, "World");  // 直接在栈中构造pair
    
    std::cout << "\n栈顶pair: " << pairStack.top().first 
              << ", " << pairStack.top().second << std::endl;
    
    return 0;
}

pop

  • 作用:移除栈顶元素,弹出并丢弃当前栈顶元素
  • 注意:不返回被移除的元素,只移除。需要先使用 top() 获取值
cpp 复制代码
#include <iostream>
#include <stack>

int main() {
    std::stack<int> numbers;
    
    // 添加元素
    for (int i = 1; i <= 5; i++) {
        numbers.push(i * 10);
        std::cout << "push(" << i * 10 << ")" << std::endl;
    }
    
    std::cout << "\n当前栈大小: " << numbers.size() << std::endl;
    std::cout << "当前栈顶: " << numbers.top() << std::endl;
    
    std::cout << "\n=== 开始pop操作 ===" << std::endl;
    
    // 安全地pop元素
    if (!numbers.empty()) {
        std::cout << "准备pop,当前栈顶: " << numbers.top() << std::endl;
        numbers.pop();  // 移除50
        std::cout << "pop后栈顶变为: " << (numbers.empty() ? "空" : std::to_string(numbers.top())) << std::endl;
    }
    
    std::cout << "\n=== 循环pop所有元素 ===" << std::endl;
    int count = 0;
    while (!numbers.empty()) {
        count++;
        std::cout << "第" << count << "次pop前,栈顶: " << numbers.top() << std::endl;
        numbers.pop();
        std::cout << "pop后栈大小: " << numbers.size() << std::endl;
    }
    
    std::cout << "\n最终栈是否为空: " << (numbers.empty() ? "是" : "否") << std::endl;
    
    return 0;
}

swap

  • 作用:交换两个栈的内容
  • 用法:高效交换两个栈的所有元素(只交换内部指针,不逐个拷贝元素)
  • 参数:要交换的另一个栈
cpp 复制代码
#include <iostream>
#include <stack>
#include <string>

int main() {
    std::stack<std::string> stack1;
    std::stack<std::string> stack2;
    
    // 初始化stack1
    stack1.push("Apple");
    stack1.push("Banana");
    stack1.push("Cherry");
    
    // 初始化stack2
    stack2.push("Dog");
    stack2.push("Cat");
    
    std::cout << "交换前:" << std::endl;
    std::cout << "stack1 大小: " << stack1.size() << ", 栈顶: " 
              << (stack1.empty() ? "空" : stack1.top()) << std::endl;
    std::cout << "stack2 大小: " << stack2.size() << ", 栈顶: " 
              << (stack2.empty() ? "空" : stack2.top()) << std::endl;
    
    // 交换两个栈的内容
    stack1.swap(stack2);
    
    std::cout << "\n交换后:" << std::endl;
    std::cout << "stack1 大小: " << stack1.size() << ", 栈顶: " 
              << (stack1.empty() ? "空" : stack1.top()) << std::endl;
    std::cout << "stack2 大小: " << stack2.size() << ", 栈顶: " 
              << (stack2.empty() ? "空" : stack2.top()) << std::endl;
    
    return 0;
}

二.queue(队列)

与栈类似,队列(queue)也是容器适配器,它提供FIFO(先进先出)的接口。这个构造函数同样有两种用法:

  1. 默认构造:创建一个空队列。

  2. 使用已有容器构造:复制容器内容作为队列的初始内容。

为什么需要基于其他容器构造队列?

  1. 队列的本质:容器适配器

队列和栈一样,是容器适配器。它基于一个底层容器(默认是deque)提供FIFO操作。这意味着队列并不关心底层数据是如何存储的,只关心如何按照先进先出的方式访问。

队列作为容器适配器,本质上是一个"FIFO规则包装器":

  • 它不创造数据存储能力,而是复用现有容器的存储

  • 它不增加新功能,而是限制功能以强化规则

  • 它不改变数据顺序,而是赋予顺序特定语义

这个构造函数允许你将任意兼容的容器瞬间转化为一个排队系统,是"数据已有,现需排队处理"场景下的优雅解决方案。它体现了软件工程中"组合优于继承"、"单一职责"等重要原则,是C++标准库中一个精心设计的抽象。

  1. 基于已有容器构造的实际意义

场景一:快速转换已有数据为队列

假设你已经有一个容器(比如vector或list)存储了一些数据,现在你需要按照先进先出的顺序处理这些数据。使用这个构造函数,你可以直接将已有容器转换为队列,而不需要逐个元素入队。

例如:

  • 你有一个存储任务的vector,现在想按照到达顺序(即vector中的顺序)处理任务,那么可以直接用vector构造队列。

场景二:复用不同底层容器

队列默认使用deque作为底层容器,但也可以指定为list或vector。不同底层容器有不同的性能特点:

  • deque(默认):两端插入删除高效,内存分段连续。

  • list:任意位置插入删除高效,但内存不连续。

  • vector:内存连续,但只能在末尾高效插入,在头部插入效率低。

如果你已经有一个list或vector,并且想用它作为队列的底层容器,这个构造函数可以让你直接使用已有容器初始化队列。

场景三:数据流水线处理

在数据处理管道中,可能前一阶段使用其他容器存储数据,后一阶段需要队列行为。使用这个构造函数可以方便地将数据转移到队列中,以便进行FIFO处理。

  1. 与栈的对比

栈是LIFO,队列是FIFO,但两者都是容器适配器。因此,这个构造函数的设计意图是相似的:允许用户从已有容器快速构建一个具有特定访问顺序(栈是后进先出,队列是先进先出)的数据结构。

  1. 注意点
  • 构造函数是explicit的,这意味着你不能隐式转换,必须显式调用构造函数。

  • 使用已有容器构造时,会复制容器中的内容。这意味着原容器和队列彼此独立,修改队列不会影响原容器,反之亦然。

底层容器的要求

队列需要一个"既能从前面拿,又能从后面放"的容器:

  • 必须支持push_back()(队尾入队)、pop_front()(队头出队)

  • 最好支持front()(查看队头)、back()(查看队尾)

这就是为什么默认用 deque(双端队列):

  • 头尾操作都高效(O(1)时间)

  • 内存动态增长,比vector更灵活

接口的精心限制

队列只暴露6个核心操作:

  1. 入队(后端插入)

  2. 出队(前端移除)

  3. 看队头(不拿走)

  4. 看队尾(不拿走)

  5. 判空

  6. 查大小

隐藏了底层容器的随机访问、中间插入删除等"破坏FIFO"的功能。

2.1.构造函数

我们创建一个队列(queue)时,可以使用这个构造函数。

cpp 复制代码
explicit queue (const container_type& ctnr = container_type());

它有两种使用方式:

  1. 默认构造:创建一个空的队列。

  2. 使用一个现有的容器(该容器类型必须与队列的底层容器类型相同)来初始化队列,队列中的元素将是该容器中元素的副本,并且顺序与容器中的顺序相同(即容器的开始处为队首,结束处为队尾)。

注意:队列是一种适配器,它默认使用deque作为底层容器,但也可以使用list等满足其操作的容器。

1.为什么是 explicit?

防止意外的隐式转换,避免歧义:

cpp 复制代码
std::deque<int> data = {1, 2, 3};
// 正确:显式构造
std::queue<int> q1(data);

// 错误:不能隐式转换(因为有explicit)
// std::queue<int> q2 = data;  // 编译错误

默认参数的作用

cpp 复制代码
std::queue<int> q1;           // 空队列,使用默认构造的deque
std::queue<int> q2(data);     // 用已有deque构造队列

基于容器构造队列时,会保持元素的原有顺序:

cpp 复制代码
std::vector<int> vec = {1, 2, 3, 4, 5};
std::queue<int, std::vector<int>> q(vec);
// 队列顺序:1 → 2 → 3 → 4 → 5
// 1会先出队,5最后出队

性能考虑

  • 构造时的复制:构造函数会复制整个容器,对于大数据集需要注意性能
  • 容器类型匹配:指定的容器类型必须支持队列所需操作(front、back、push_back、pop_front)

我们现在直接看例子

cpp 复制代码
#include <iostream>
#include <queue>
#include <deque>
#include <list>

int main() {
    // 1. 默认构造 - 空队列
    std::queue<int> q1;  // 使用默认的deque作为底层容器
    std::cout << "q1 size: " << q1.size() << std::endl;  // 输出: 0
    
    // 2. 使用list作为底层容器(指定容器类型)
    std::queue<int, std::list<int>> q2;
    std::cout << "q2 size: " << q2.size() << std::endl;  // 输出: 0
    
    // 3. 使用已有容器初始化(复制容器内容)
    std::deque<int> deq = {1, 2, 3, 4, 5};
    std::queue<int> q3(deq);  // 使用deque初始化队列
    
    std::cout << "q3 size: " << q3.size() << std::endl;  // 输出: 5
    
    // 查看队首元素(应该是deq的第一个元素)
    std::cout << "q3 front: " << q3.front() << std::endl;  // 输出: 1
    
    // 4. 使用list初始化
    std::list<int> lst = {10, 20, 30};
    std::queue<int, std::list<int>> q4(lst);  // 使用list初始化队列
    
    std::cout << "q4 front: " << q4.front() << std::endl;  // 输出: 10
    
    // 5. 出队元素验证队列的顺序(FIFO)
    std::cout << "\n出队q3元素: ";
    while (!q3.empty()) {
        std::cout << q3.front() << " ";
        q3.pop();
    }
    // 输出: 1 2 3 4 5 (先进先出)
    
    return 0;
}

2.2.常用操作

作为一个容器适配器,queue提供了一些队列专有的操作

empty

  • 作用:检查队列是否为空

  • 详细说明:判断队列中是否有元素。这是一个安全保护函数,在进行任何可能访问或移除元素的操作之前,都应该先用这个函数检查队列是否为空,避免对空队列进行操作导致程序错误

cpp 复制代码
#include <iostream>
#include <queue>
#include <string>

int main() {
    std::queue<int> numberQueue;
    std::queue<std::string> textQueue;
    
    std::cout << "=== empty() 方法演示 ===" << std::endl;
    
    // 示例1: 检查空队列
    std::cout << "\n1. 检查空队列:" << std::endl;
    if (numberQueue.empty()) {
        std::cout << "数字队列是空的" << std::endl;  // 会执行这里
    } else {
        std::cout << "数字队列不是空的" << std::endl;
    }
    
    // 示例2: 添加元素后检查
    std::cout << "\n2. 添加元素后检查:" << std::endl;
    numberQueue.push(100);
    
    if (!numberQueue.empty()) {
        std::cout << "现在数字队列不是空的" << std::endl;  // 会执行这里
    }
    
    // 示例3: 清空队列后检查
    std::cout << "\n3. 清空队列后检查:" << std::endl;
    numberQueue.pop();  // 移除唯一元素
    
    if (numberQueue.empty()) {
        std::cout << "数字队列又变成空的了" << std::endl;  // 会执行这里
    }
    
    // 示例4: 实际应用中的安全检查
    std::cout << "\n4. 队列操作前的安全检查:" << std::endl;
    
    // 错误做法:直接访问空队列
    // std::cout << "队首元素: " << numberQueue.front() << std::endl;  // 可能导致崩溃
    
    // 正确做法:先检查是否为空
    if (!textQueue.empty()) {
        std::cout << "文本队首: " << textQueue.front() << std::endl;
    } else {
        std::cout << "文本队列为空,无法访问队首" << std::endl;  // 会执行这里
    }
    
    // 添加一些数据
    textQueue.push("第一条消息");
    textQueue.push("第二条消息");
    
    // 现在可以安全访问
    if (!textQueue.empty()) {
        std::cout << "添加数据后,队首: " << textQueue.front() << std::endl;
    }
    
    return 0;
}

size

  • 作用:返回队列中当前元素的个数

  • 详细说明:返回队列包含的元素数量。这个值是一个非负整数,表示队列的长度。随着元素的入队和出队,这个值会动态变化

cpp 复制代码
#include <iostream>
#include <queue>

int main() {
    std::queue<int> queue;
    
    std::cout << "=== size() 方法演示 ===" << std::endl;
    
    // 示例1: 初始大小
    std::cout << "\n1. 初始队列大小:" << std::endl;
    std::cout << "队列初始大小: " << queue.size() << std::endl;  // 输出: 0
    
    // 示例2: 添加元素
    std::cout << "\n2. 添加元素:" << std::endl;
    queue.push(10);
    std::cout << "push(10)后大小: " << queue.size() << std::endl;  // 输出: 1
    
    queue.push(20);
    queue.push(30);
    std::cout << "再push(20), push(30)后大小: " << queue.size() << std::endl;  // 输出: 3
    
    // 示例3: 移除元素
    std::cout << "\n3. 移除元素:" << std::endl;
    queue.pop();
    std::cout << "pop()后大小: " << queue.size() << std::endl;  // 输出: 2
    
    // 示例4: 批量操作
    std::cout << "\n4. 批量操作:" << std::endl;
    for (int i = 4; i <= 7; i++) {
        queue.push(i * 10);
        std::cout << "push(" << i * 10 << ")后大小: " << queue.size() << std::endl;
    }
    
    // 示例5: 清空队列
    std::cout << "\n5. 清空队列:" << std::endl;
    while (!queue.empty()) {
        queue.pop();
        std::cout << "pop()后大小: " << queue.size() << std::endl;
    }
    
    std::cout << "\n最终队列大小: " << queue.size() << std::endl;
    
    return 0;
}

front

  • 作用:访问队头元素(下一个要处理的元素),返回这个元素的引用

  • 详细说明 :返回队列中最先进入的那个元素,也就是下一个将要被处理的元素。这个操作只查看不删除元素。如果队列为空时调用这个函数,结果是未定义的,可能导致程序崩溃

back

  • 作用:访问队尾元素(最后加入的元素),返回这个元素的引用

  • 详细说明 :返回队列中最后进入的那个元素。与front相反,back查看的是最近添加的元素。同样,这个操作只查看不删除元素,对空队列调用也会导致未定义行为

cpp 复制代码
#include <iostream>
#include <queue>
#include <string>

int main() {
    std::queue<int> numbers;
    
    std::cout << "=== front() 和 back() 基本示例 ===" << std::endl;
    
    // 添加元素
    numbers.push(10);
    numbers.push(20);
    numbers.push(30);
    numbers.push(40);
    numbers.push(50);
    
    std::cout << "添加元素: 10, 20, 30, 40, 50" << std::endl;
    
    // 查看队头和队尾
    std::cout << "\n队列当前状态:" << std::endl;
    std::cout << "队头 (front): " << numbers.front() << " (最先进入的元素)" << std::endl;
    std::cout << "队尾 (back): " << numbers.back() << " (最后进入的元素)" << std::endl;
    std::cout << "队列大小: " << numbers.size() << std::endl;
    
    // 修改队头元素
    std::cout << "\n修改队头元素为 100:" << std::endl;
    numbers.front() = 100;
    std::cout << "新的队头: " << numbers.front() << std::endl;
    
    // 修改队尾元素
    std::cout << "\n修改队尾元素为 500:" << std::endl;
    numbers.back() = 500;
    std::cout << "新的队尾: " << numbers.back() << std::endl;
    
    // 处理队列
    std::cout << "\n处理队列 (FIFO):" << std::endl;
    while (!numbers.empty()) {
        std::cout << "处理: " << numbers.front() << " (队尾是: " << numbers.back() << ")" << std::endl;
        numbers.pop();
    }
    
    return 0;
}

push

  • 作用:插入元素到队尾

  • 详细说明:将一个新元素添加到队列的末尾。新加入的元素会成为新的队尾元素,按照先进先出的规则,它将在所有已有元素之后被处理

  • 使用场景:将新的任务、消息或数据加入等待队列

cpp 复制代码
#include <iostream>
#include <queue>

int main() {
    std::queue<int> q;

    // 使用 push 添加元素到队尾
    q.push(10);
    q.push(20);
    q.push(30);

    std::cout << "队列大小: " << q.size() << std::endl;
    std::cout << "队头元素: " << q.front() << std::endl; // 10
    std::cout << "队尾元素: " << q.back() << std::endl;  // 30

    return 0;
}

emplace

  • 作用:在队尾直接构造元素(原地构造)

  • 详细说明 :这是一个比push更高效的操作。它直接在队列的尾部位置构造新元素,避免了先创建临时对象再复制或移动的过程。特别是对于复杂的对象类型,这个操作可以显著提高性能

  • 使用场景:向队列中添加构造成本较高的复杂对象

cpp 复制代码
#include <iostream>
#include <queue>
#include <string>

class Person {
public:
    Person(std::string name, int age) : name(name), age(age) {
        std::cout << "构造 Person: " << name << std::endl;
    }

    // 拷贝构造函数
    Person(const Person& other) : name(other.name), age(other.age) {
        std::cout << "拷贝构造 Person: " << name << std::endl;
    }

    // 移动构造函数
    Person(Person&& other) noexcept : name(std::move(other.name)), age(other.age) {
        std::cout << "移动构造 Person: " << name << std::endl;
    }

    void print() const {
        std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
    }

private:
    std::string name;
    int age;
};

int main() {
    std::queue<Person> q;

    std::cout << "使用 push:" << std::endl;
    Person p1("Alice", 25);
    q.push(p1);  // 这里会调用拷贝构造函数

    std::cout << "\n使用 push 移动语义:" << std::endl;
    Person p2("Bob", 30);
    q.push(std::move(p2));  // 这里会调用移动构造函数

    std::cout << "\n使用 emplace:" << std::endl;
    q.emplace("Charlie", 35);  // 直接在队列中构造,没有拷贝或移动

    std::cout << "\n队列中的元素:" << std::endl;
    // 注意:queue 没有迭代器,所以只能通过 front 和 pop 来访问
    while (!q.empty()) {
        q.front().print();
        q.pop();
    }

    return 0;
}

pop

  • 作用:移除队头元素

  • 详细说明 :将队列最前端的元素移除。注意:这个函数不返回被移除的元素值 ,只是简单地将它从队列中删除。如果需要获取被移除的元素值,必须先用front获取值,再调用pop移除

  • 使用场景:完成一个任务或处理完一条消息后,将其从队列中移出

cpp 复制代码
#include <iostream>
#include <queue>

int main() {
    std::queue<int> q;

    // 添加元素
    for (int i = 1; i <= 5; ++i) {
        q.push(i * 10);
    }

    std::cout << "初始队列大小: " << q.size() << std::endl;

    // 处理队列中的元素
    while (!q.empty()) {
        std::cout << "处理队头元素: " << q.front() << std::endl;
        q.pop();  // 移除队头元素
        std::cout << "移除后队列大小: " << q.size() << std::endl;
    }

    // 注意:对空队列调用 pop 是未定义行为
    // q.pop(); // 错误!

    return 0;
}

swap

  • 作用:交换两个队列的内容

  • 详细说明:将当前队列与另一个队列的所有元素进行交换。这个操作非常高效,因为它通常只交换两个队列的内部数据结构指针,而不是逐个复制所有元素

  • 使用场景:快速切换两个工作队列,或者在需要清空队列时使用交换技巧

cpp 复制代码
#include <iostream>
#include <queue>
#include <string>

int main() {
    std::queue<std::string> queueA;
    std::queue<std::string> queueB;
    
    // 初始化queueA
    queueA.push("任务A1");
    queueA.push("任务A2");
    queueA.push("任务A3");
    
    // 初始化queueB
    queueB.push("任务B1");
    queueB.push("任务B2");
    
    std::cout << "交换前:" << std::endl;
    std::cout << "queueA 大小: " << queueA.size() 
              << ", 队头: " << (queueA.empty() ? "空" : queueA.front())
              << ", 队尾: " << (queueA.empty() ? "空" : queueA.back()) << std::endl;
    std::cout << "queueB 大小: " << queueB.size()
              << ", 队头: " << (queueB.empty() ? "空" : queueB.front())
              << ", 队尾: " << (queueB.empty() ? "空" : queueB.back()) << std::endl;
    
    // 交换两个队列的内容
    queueA.swap(queueB);
    
    std::cout << "\n交换后:" << std::endl;
    std::cout << "queueA 大小: " << queueA.size()
              << ", 队头: " << (queueA.empty() ? "空" : queueA.front())
              << ", 队尾: " << (queueA.empty() ? "空" : queueA.back()) << std::endl;
    std::cout << "queueB 大小: " << queueB.size()
              << ", 队头: " << (queueB.empty() ? "空" : queueB.front())
              << ", 队尾: " << (queueB.empty() ? "空" : queueB.back()) << std::endl;
    
    // 使用std::swap也可以
    std::cout << "\n使用std::swap再次交换:" << std::endl;
    std::swap(queueA, queueB);
    
    std::cout << "queueA 队头: " << (queueA.empty() ? "空" : queueA.front()) << std::endl;
    std::cout << "queueB 队头: " << (queueB.empty() ? "空" : queueB.front()) << std::endl;
    
    return 0;
}

三.priority_queue(优先级队列)

请注意,queue是先进先出(FIFO)的队列,而priority_queue是优先级队列(元素按优先级排序,每次访问优先级最高的元素)。下面我们从多个维度进行比较。

  1. 访问顺序

    • queue:严格遵循先进先出(FIFO)的顺序。最先插入的元素最先被移除。

    • priority_queue:元素被赋予优先级。每次访问和移除的都是当前队列中优先级最高的元素(默认是最大的元素,即最大堆)。插入顺序并不影响移除顺序。

  2. 底层实现

    • queue:默认使用deque作为底层容器,但也可以使用list或其他满足queue操作的容器。

    • priority_queue:默认使用vector作为底层容器,并且使用堆算法(heap)来维护元素的优先级顺序。也可以使用deque,但vector通常性能更好。

3.1.构造函数

那么对于这个优先级队列,其实是有两种构造函数的

也就是下面这2种:

cpp 复制代码
// 初始化构造函数(最常用)
explicit priority_queue(const Compare& comp = Compare(),
                        const Container& ctnr = Container());

// 范围构造函数
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last,
               const Compare& comp = Compare(),
               const Container& ctnr = Container());

首先我们看看这个初始化构造函数的

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>
#include <functional>  // for greater

int main() 
{
    std::cout << "=== priority_queue 初始化构造函数示例 ===\n" << std::endl;
    
    // 1.1 默认构造 - 最大堆(最大元素在顶部)
    std::priority_queue<int> pq1;
    std::cout << "1. 默认构造的最大堆 priority_queue" << std::endl;
    pq1.push(1);
    pq1.push(2);
    pq1.push(3);
    pq1.push(4);
    std::cout << "   顶部元素: " << pq1.top() << std::endl;  // 应该是 4

    // 1.2 指定比较函数 - 最小堆(最小元素在顶部)
    std::priority_queue<int, std::vector<int>, std::greater<int>> pq2;
    std::cout << "2. 最小堆 priority_queue (使用 std::greater<int>)" << std::endl;
    pq2.push(1);
    pq2.push(2);
    pq2.push(3);
    pq2.push(4);
    std::cout << "   顶部元素: " << pq2.top() << std::endl;  // 应该是 1

    
    // 1.3 使用已有容器初始化(注意:需要手动建堆)
    std::vector<int> vec = {30, 10, 50, 20, 40};
    std::priority_queue<int> pq3(std::less<int>(), vec);//最大堆
    std::cout << "3. 使用 vector 初始化的 priority_queue" << std::endl;
    std::cout << "   容器初始内容: ";
    for (int num : vec) std::cout << num << " ";
    std::cout << std::endl;
    std::cout << "   优先队列顶部: " << pq3.top() << std::endl;  // 应该是 50(最大堆)
    
    // 1.4 自定义比较函数
    struct CustomCompare {
        bool operator()(int a, int b) {
            // 按照个位数大小排序(个位数小的优先级高)
            return (a % 10) > (b % 10);
        }
    };
    
    std::priority_queue<int, std::vector<int>, CustomCompare> pq4;
    pq4.push(25);
    pq4.push(17);
    pq4.push(32);
    pq4.push(46);
    
    std::cout << "\n4. 自定义比较函数的 priority_queue" << std::endl;
    std::cout << "   比较规则:按个位数从小到大排序" << std::endl;
    std::cout << "   元素: 25, 17, 32, 46" << std::endl;
    std::cout << "   顶部元素: " << pq4.top() << std::endl;  // 应该是 32(个位是2)
    
    return 0;
}

然后我们看这个范围构造函数的

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>
#include <list>
#include <array>
#include <functional>

int main() {
    std::cout << "=== priority_queue 范围构造函数示例 ===\n" << std::endl;
    
    // 2.1 使用 vector 的范围初始化
    std::vector<int> vec = {70, 20, 90, 10, 50};
    std::priority_queue<int> pq1(vec.begin(), vec.end());
    
    std::cout << "1. 使用 vector 范围构造的最大堆:" << std::endl;
    std::cout << "   原始数据: ";
    for (int num : vec) std::cout << num << " ";
    std::cout << "\n   顶部元素(最大): " << pq1.top() << std::endl;  // 90
    
    // 2.2 使用 list 的范围初始化最小堆
    std::list<int> lst = {15, 35, 5, 45, 25};
    std::priority_queue<int, std::vector<int>, std::greater<int>> 
        pq2(lst.begin(), lst.end());
    
    std::cout << "\n2. 使用 list 范围构造的最小堆:" << std::endl;
    std::cout << "   原始数据: ";
    for (int num : lst) std::cout << num << " ";
    std::cout << "\n   顶部元素(最小): " << pq2.top() << std::endl;  // 5
    
    // 2.3 使用数组的范围初始化
    int arr[] = {100, 60, 80, 40, 120};
    std::priority_queue<int> pq3(arr, arr + 5);
    
    std::cout << "\n3. 使用数组范围构造的最大堆:" << std::endl;
    std::cout << "   原始数据: ";
    for (int i = 0; i < 5; i++) std::cout << arr[i] << " ";
    std::cout << "\n   顶部元素(最大): " << pq3.top() << std::endl;  // 120
    
    // 2.4 使用 array 的范围初始化
    std::array<int, 6> arr2 = {88, 33, 66, 99, 11, 55};
    std::priority_queue<int> pq4(arr2.begin(), arr2.end());
    
    std::cout << "\n4. 使用 array 范围构造的最大堆:" << std::endl;
    std::cout << "   原始数据: ";
    for (int num : arr2) std::cout << num << " ";
    std::cout << "\n   顶部元素(最大): " << pq4.top() << std::endl;  // 99
    
    // 2.5 结合比较函数和容器
    std::vector<int> vec2 = {200, 150, 300, 100, 250};
    
    // 使用范围和比较函数构造最小堆
    std::priority_queue<int, std::vector<int>, std::greater<int>> 
        pq5(vec2.begin(), vec2.end(), std::greater<int>());
    
    std::cout << "\n5. 指定范围和比较函数的最小堆:" << std::endl;
    std::cout << "   原始数据: ";
    for (int num : vec2) std::cout << num << " ";
    std::cout << "\n   顶部元素(最小): " << pq5.top() << std::endl;  // 100
    
    return 0;
}

3.3.常用操作

作为容器适配器,这个优先级队列也是提供了一些常用的接口

empty

  • 作用:检查优先队列是否为空

  • 详细说明 :判断优先队列中是否有元素。这是进行任何操作前的安全检查,因为对空优先队列调用top()pop()会导致未定义行为

  • 使用场景:在尝试访问或弹出元素前检查队列状态

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>
#include <functional>

int main() {
    std::cout << "=== priority_queue::empty() 方法示例 ===\n" << std::endl;
    
    // 1.1 创建不同优先队列
    std::priority_queue<int> maxHeap;  // 最大堆
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;  // 最小堆
    
    std::cout << "1. 初始状态检查:" << std::endl;
    std::cout << "最大堆是否为空: " << (maxHeap.empty() ? "是" : "否") << std::endl;
    std::cout << "最小堆是否为空: " << (minHeap.empty() ? "是" : "否") << std::endl;
    
    // 1.2 添加元素后检查
    maxHeap.push(10);
    minHeap.push(10);
    
    std::cout << "\n2. 添加元素后检查:" << std::endl;
    std::cout << "最大堆是否为空: " << (maxHeap.empty() ? "是" : "否") << std::endl;
    std::cout << "最小堆是否为空: " << (minHeap.empty() ? "是" : "否") << std::endl;
    
    // 1.3 安全操作示例
    std::cout << "\n3. 安全操作示例:" << std::endl;
    
    // 错误示例:直接调用 top() 或 pop() 可能导致崩溃
    // std::priority_queue<int> emptyQueue;
    // int value = emptyQueue.top();  // 未定义行为!
    // emptyQueue.pop();              // 未定义行为!
    
    // 正确做法:先检查是否为空
    std::priority_queue<int> safeQueue;
    
    if (!safeQueue.empty()) {
        std::cout << "顶部元素: " << safeQueue.top() << std::endl;
        safeQueue.pop();
    } else {
        std::cout << "队列为空,无法访问顶部元素" << std::endl;
    }
    
    // 1.4 清空队列检查
    std::cout << "\n4. 清空队列检查:" << std::endl;
    while (!maxHeap.empty()) {
        maxHeap.pop();
    }
    std::cout << "清空后最大堆是否为空: " << (maxHeap.empty() ? "是" : "否") << std::endl;
    
    return 0;
}

size

  • 作用:返回优先队列中当前元素的个数

  • 详细说明:返回队列包含的元素数量。这个值随着元素的插入和删除动态变化

  • 使用场景:监控队列规模,控制内存使用或处理进度

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>

int main() {
    std::cout << "=== priority_queue::size() 方法示例 ===\n" << std::endl;
    
    std::priority_queue<int> pq;
    
    // 2.1 初始大小
    std::cout << "1. 初始队列大小: " << pq.size() << std::endl;
    
    // 2.2 添加元素
    std::cout << "\n2. 添加元素:" << std::endl;
    for (int i = 1; i <= 5; i++) {
        pq.push(i * 10);
        std::cout << "push(" << i * 10 << ") 后,队列大小: " << pq.size() << std::endl;
    }
    
    // 2.3 删除元素
    std::cout << "\n3. 删除元素:" << std::endl;
    while (!pq.empty()) {
        std::cout << "当前大小: " << pq.size() 
                  << ",顶部元素: " << pq.top() << std::endl;
        pq.pop();
    }
    
    // 2.4 批量操作与大小监控
    std::cout << "\n4. 批量操作与大小监控:" << std::endl;
    std::vector<int> data = {25, 15, 35, 5, 45, 20, 30, 10, 40};
    
    for (int value : data) {
        pq.push(value);
        std::cout << "添加 " << value << ",当前大小: " << pq.size();
        if (!pq.empty()) {
            std::cout << ",当前顶部: " << pq.top();
        }
        std::cout << std::endl;
    }
    
    std::cout << "\n最终队列大小: " << pq.size() << std::endl;
    
    return 0;
}

top

  • 作用:访问优先级最高的元素(堆顶元素),注意:不能通过top()函数来堆这个优先级最高的元素进行修改。

  • 返回优先队列中优先级最高的元素(堆顶元素),但不删除它。默认情况下(最大堆)返回的是当前队列中的最大元素。

  • 详细说明 :返回优先队列中优先级最高 的元素。注意:优先队列不保证先进先出 ,而是保证每次访问的都是当前队列中优先级最高的元素。默认情况下是最大元素(最大堆)。这个操作只查看不删除元素

  • 使用场景:查看下一个要处理的高优先级任务

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>

int main() {
    std::cout << "=== priority_queue::top() 基本示例 ===\n" << std::endl;
    
    // 1. 最大堆(默认)- 顶部是最大元素
    std::priority_queue<int> maxHeap;
    
    maxHeap.push(30);
    maxHeap.push(10);
    maxHeap.push(50);
    maxHeap.push(20);
    maxHeap.push(40);
    
    std::cout << "1. 最大堆示例:" << std::endl;
    std::cout << "元素: 30, 10, 50, 20, 40" << std::endl;
    std::cout << "顶部元素(最大): " << maxHeap.top() << std::endl;  // 输出: 50
    
    // 2. 最小堆 - 顶部是最小元素
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
    
    minHeap.push(30);
    minHeap.push(10);
    minHeap.push(50);
    minHeap.push(20);
    minHeap.push(40);
    
    std::cout << "\n2. 最小堆示例:" << std::endl;
    std::cout << "元素: 30, 10, 50, 20, 40" << std::endl;
    std::cout << "顶部元素(最小): " << minHeap.top() << std::endl;  // 输出: 10
    
    // 3. 查看但不删除
    std::cout << "\n3. 查看但不删除演示:" << std::endl;
    std::priority_queue<int> pq;
    pq.push(100);
    pq.push(200);
    pq.push(300);
    
    std::cout << "初始顶部: " << pq.top() << std::endl;  // 300
    std::cout << "再次查看顶部: " << pq.top() << std::endl;  // 还是300
    std::cout << "队列大小: " << pq.size() << std::endl;  // 3
    
    return 0;
}

push

  • 作用:插入元素到优先队列

  • 详细说明:将一个新元素添加到优先队列中。新元素的位置不是固定的,而是根据其优先级自动调整到合适位置(堆化过程)

  • 使用场景:将新任务或数据加入优先队列,让系统按优先级处理

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>

int main() {
    std::cout << "=== priority_queue::push() 方法示例 ===\n" << std::endl;
    
    // 1.1 最大堆(默认)
    std::priority_queue<int> maxHeap;
    
    std::cout << "1. 最大堆 push 示例:" << std::endl;
    maxHeap.push(30);
    std::cout << "push(30) 后,顶部: " << maxHeap.top() 
              << ",大小: " << maxHeap.size() << std::endl;
    
    maxHeap.push(10);
    std::cout << "push(10) 后,顶部: " << maxHeap.top() 
              << ",大小: " << maxHeap.size() << std::endl;
    
    maxHeap.push(50);
    std::cout << "push(50) 后,顶部: " << maxHeap.top() 
              << ",大小: " << maxHeap.size() << std::endl;
    
    maxHeap.push(20);
    std::cout << "push(20) 后,顶部: " << maxHeap.top() 
              << ",大小: " << maxHeap.size() << std::endl;
    
    // 1.2 最小堆
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
    
    std::cout << "\n2. 最小堆 push 示例:" << std::endl;
    minHeap.push(30);
    std::cout << "push(30) 后,顶部: " << minHeap.top() 
              << ",大小: " << minHeap.size() << std::endl;
    
    minHeap.push(10);
    std::cout << "push(10) 后,顶部: " << minHeap.top() 
              << ",大小: " << minHeap.size() << std::endl;
    
    minHeap.push(50);
    std::cout << "push(50) 后,顶部: " << minHeap.top() 
              << ",大小: " << minHeap.size() << std::endl;
    
    // 1.3 批量 push 示例
    std::cout << "\n3. 批量 push 示例:" << std::endl;
    std::priority_queue<int> batchHeap;
    std::vector<int> numbers = {25, 15, 35, 5, 45, 20, 30};
    
    for (int num : numbers) {
        batchHeap.push(num);
        std::cout << "push(" << num << ") 后,顶部: " << batchHeap.top() 
                  << ",大小: " << batchHeap.size() << std::endl;
    }
    
    return 0;
}

emplace

  • 作用:在优先队列中直接构造元素(原地构造)

  • 详细说明 :比push更高效的操作,直接在优先队列中构造新元素,避免了创建临时对象再复制的开销。元素构造后会根据优先级自动调整位置

  • 使用场景:向优先队列中添加构造复杂的对象,提高性能

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>
#include <functional>

int main() {
    std::cout << "=== priority_queue::emplace() 基础数据类型示例 ===\n" << std::endl;
    
    // 1.1 最大堆 emplace 示例
    std::priority_queue<int> maxHeap;
    
    std::cout << "1. 最大堆 emplace 示例:" << std::endl;
    maxHeap.emplace(30);
    std::cout << "emplace(30) 后,顶部: " << maxHeap.top() 
              << ",大小: " << maxHeap.size() << std::endl;
    
    maxHeap.emplace(10);
    std::cout << "emplace(10) 后,顶部: " << maxHeap.top() 
              << ",大小: " << maxHeap.size() << std::endl;
    
    maxHeap.emplace(50);
    std::cout << "emplace(50) 后,顶部: " << maxHeap.top() 
              << ",大小: " << maxHeap.size() << std::endl;
    
    // 1.2 最小堆 emplace 示例
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
    
    std::cout << "\n2. 最小堆 emplace 示例:" << std::endl;
    minHeap.emplace(30);
    std::cout << "emplace(30) 后,顶部: " << minHeap.top() 
              << ",大小: " << minHeap.size() << std::endl;
    
    minHeap.emplace(10);
    std::cout << "emplace(10) 后,顶部: " << minHeap.top() 
              << ",大小: " << minHeap.size() << std::endl;
    
    minHeap.emplace(50);
    std::cout << "emplace(50) 后,顶部: " << minHeap.top() 
              << ",大小: " << minHeap.size() << std::endl;
    
    return 0;
}

pop

  • 作用:移除优先级最高的元素(堆顶元素)

  • 详细说明 :删除当前优先队列中优先级最高的元素。注意:这个函数不返回被移除的元素值,只是将它从队列中删除。移除后,队列会自动重新调整,使新的最高优先级元素上升到顶部

  • 使用场景:处理完一个高优先级任务后,将其从队列中移除

cpp 复制代码
#include <iostream>
#include <queue>
#include <chrono>
#include <thread>

int main() {
    std::cout << "=== priority_queue::pop() 方法示例 ===\n" << std::endl;
    
    std::priority_queue<int> pq;
    
    // 添加元素
    std::cout << "1. 添加元素到优先队列:" << std::endl;
    for (int i = 1; i <= 8; i++) {
        int value = i * 10;
        pq.push(value);
        std::cout << "push(" << value << "),当前顶部: " << pq.top() 
                  << ",大小: " << pq.size() << std::endl;
    }
    
    std::cout << "\n2. 开始 pop 操作 (从高到低移除):" << std::endl;
    
    int count = 0;
    while (!pq.empty()) {
        count++;
        
        // 先查看顶部元素
        std::cout << "第" << count << "次 pop 前:" << std::endl;
        std::cout << "  顶部元素: " << pq.top() << std::endl;
        std::cout << "  队列大小: " << pq.size() << std::endl;
        
        // 移除顶部元素
        pq.pop();
        
        // 查看移除后的状态
        if (!pq.empty()) {
            std::cout << "  pop 后新的顶部: " << pq.top() 
                      << ",剩余大小: " << pq.size() << std::endl;
        } else {
            std::cout << "  pop 后队列为空" << std::endl;
        }
        std::cout << std::endl;
    }
    
    std::cout << "3. 错误使用示例:" << std::endl;
    std::priority_queue<int> emptyQueue;
    
    // 错误1: 对空队列调用 pop()
    // emptyQueue.pop();  // 未定义行为!可能导致崩溃
    
    // 错误2: 试图获取 pop() 的返回值
    // int value = emptyQueue.pop();  // 错误!pop() 不返回值
    
    std::cout << "正确做法:先用 empty() 检查,再 top() 获取值,最后 pop()" << std::endl;
    
    return 0;
}

swap

  • 作用:交换两个优先队列的内容

  • 详细说明:将当前优先队列与另一个优先队列的所有元素进行交换。这个操作通常只交换内部数据结构指针,而不是逐个复制元素,因此非常高效

  • 使用场景:快速切换两个工作队列,或在特定算法中交换数据

cpp 复制代码
#include <iostream>
#include <queue>
#include <vector>

int main() {
    std::cout << "=== priority_queue::swap() 基本示例 ===\n" << std::endl;
    
    // 1. 创建两个优先队列
    std::priority_queue<int> pq1;
    std::priority_queue<int> pq2;
    
    // 填充数据
    pq1.push(10);
    pq1.push(20);
    pq1.push(30);
    
    pq2.push(100);
    pq2.push(200);
    pq2.push(300);
    pq2.push(400);
    
    std::cout << "交换前:" << std::endl;
    std::cout << "pq1 大小: " << pq1.size() 
              << ", 顶部: " << (pq1.empty() ? "空" : std::to_string(pq1.top())) << std::endl;
    std::cout << "pq2 大小: " << pq2.size()
              << ", 顶部: " << (pq2.empty() ? "空" : std::to_string(pq2.top())) << std::endl;
    
    // 交换两个优先队列
    pq1.swap(pq2);
    
    std::cout << "\n交换后:" << std::endl;
    std::cout << "pq1 大小: " << pq1.size()
              << ", 顶部: " << (pq1.empty() ? "空" : std::to_string(pq1.top())) << std::endl;
    std::cout << "pq2 大小: " << pq2.size()
              << ", 顶部: " << (pq2.empty() ? "空" : std::to_string(pq2.top())) << std::endl;
    
    // 也可以使用 std::swap
    std::cout << "\n使用 std::swap 再次交换:" << std::endl;
    std::swap(pq1, pq2);
    
    std::cout << "pq1 顶部: " << (pq1.empty() ? "空" : std::to_string(pq1.top())) << std::endl;
    std::cout << "pq2 顶部: " << (pq2.empty() ? "空" : std::to_string(pq2.top())) << std::endl;
    
    return 0;
}
相关推荐
寻寻觅觅☆14 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc15 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
l1t15 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿15 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar12316 小时前
C++使用format
开发语言·c++·算法
码说AI16 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS16 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
lanhuazui1016 小时前
C++ 中什么时候用::(作用域解析运算符)
c++
charlee4416 小时前
从零实现一个生产级 RAG 语义搜索系统:C++ + ONNX + FAISS 实战
c++·faiss·onnx·rag·语义搜索
星空下的月光影子17 小时前
易语言开发从入门到精通:补充篇·网络爬虫与自动化采集分析系统深度实战·HTTP/HTTPS请求·HTML/JSON解析·反爬策略·电商价格监控·新闻资讯采集
开发语言