栈、队列、优先级队列详解【c++】

栈、队列、优先级队列详解【c++】_第1张图片


目录

  • stack的介绍和使用
    • ⚽stack的介绍
    • ⚽stack的使用
  • queue的介绍和使用
    • ⚽queue的介绍
    • ⚽queue的使用
  • priority_queue的介绍和使用
    • ⚽priority_queue的介绍
    • ⚽priority_queue的使用
  • 总结


stack的介绍和使用

⚽stack的介绍

stack是一种容器适配器,它专门用于实现后进先出(LIFO)的数据结构。stack是通过封装底层容器的方式实现的,它提供了一组特定的成员函数来访问其元素,将元素作为其底层容器的尾部(即栈顶)被压入和弹出。

stack的底层容器可以是任何标准的容器类模板或其他特定的容器类,这些容器类应该支持以下操作:

  1. empty:判空操作
  2. back:获取尾部元素操作
  3. push_back:尾部插入元素操作
  4. pop_back:尾部删除元素操作

栈、队列、优先级队列详解【c++】_第2张图片

标准容器vector、deque、list均符合这些需求。如果没有为stack指定特定的底层容器,默认情况下将使用deque作为底层容器。

⚽stack的使用

栈是一种常见的数据结构,它是一种后进先出(LIFO)的数据结构,即最后进入的元素最先被访问。栈通常用于函数调用、表达式求值、括号匹配、迷宫问题等场景中。

stack给我们提供了以下几个函数:

函数说明 接口说明
stack() 构造空的栈
empty() 检测stack是否为空
size() 返回stack中元素的个数
top() 返回栈顶元素的引用
push() 将元素val压入stack中
pop() 将stack中尾部的元素弹出

示例代码:

#include 
#include 
using namespace std;

int main()
{
    // 创建一个空的栈
    stack<int> s;
    // 检查栈是否为空
    if (s.empty())
    {
        cout << "栈为空" << endl;
    }
    // 将元素压入栈中
    s.push(1);
    s.push(2);
    s.push(3);
    // 获取栈中元素的数量
    cout << "栈中元素的数量为:" << s.size() << endl;
    // 获取栈顶元素的引用
    cout << "栈顶元素为:" << s.top() << endl;
    // 弹出栈顶元素
    s.pop();
    cout << "弹出栈顶元素" << endl;
    // 获取栈中元素的数量
    cout << "栈中元素的数量为:" << s.size() << endl;
    // 再次获取栈顶元素的引用
    cout << "栈顶元素为:" << s.top() << endl;
    return 0;
}

运行结果:

栈、队列、优先级队列详解【c++】_第3张图片

在使用stack时,需要注意以下几点:

  1. 栈是一种后进先出(LIFO)的数据结构。
  2. 在使用栈之前,需要包含头文件。
  3. stack模板类只能存储相同类型的元素。
  4. 当栈为空时,调用top()函数会导致未定义的行为。

queue的介绍和使用

⚽queue的介绍

队列(Queue)是一种常用的数据结构,它遵循先进先出(First In First Out,FIFO)的原则,即先进入队列的元素先出队列。队列可以用于实现很多算法和数据结构,例如广度优先搜索和缓存等。在C++中,可以使用STL中的queue容器适配器来实现队列。

queue作为容器适配器实现,可以将其底层容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。

底层容器可以是标准容器类模板之一,例如deque和list,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:

  • empty():检测队列是否为空。
  • size():返回队列中有效元素的个数。
  • front():返回队头元素的引用。
  • back():返回队尾元素的引用。
  • push_back(const T& obj):在队列尾部插入元素obj。
  • pop_front():在队列头部弹出元素。

在这里插入图片描述

默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

⚽queue的使用

使用queue非常简单,只需要先创建一个queue对象,然后使用push()方法向队列中添加元素,使用pop()方法从队列中删除元素,使用front()和back()方法获取队头和队尾元素的引用。以下是queue提供给我们的一些函数方法。

函数声明 接口说明
queue() 构造空的队列
empty() 检测队列是否为空,是返回true,否则返回false
size() 返回队列中有效元素的个数
front() 返回队头元素的引用
back() 返回队尾元素的引用
push() 在队尾将元素val入队列
pop() 将队头元素出队列

示例代码:

#include 
#include 
using namespace std;

int main() {
    queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);
    cout << "队列大小:" << q.size() << endl;  
    cout << "队头元素:" << q.front() << endl;  
    cout << "队尾元素:" << q.back() << endl;  
    q.pop();
    cout << "删除队头元素后,队列大小:" << q.size() << endl; 
    cout << "新的队头元素:" << q.front() << endl;  
    return 0;
}

运行代码:

栈、队列、优先级队列详解【c++】_第4张图片

queue使用的注意事项:

  1. 使用前需要包含头文件。
  2. queue是一种FIFO(先进先出)的数据结构,只能在队列的末尾添加元素,在队列的头部删除元素。
  3. queue的底层实现可以是deque或list,因此可以根据需要选择适合的底层实现。默认情况下,使用deque作为底层实现。
  4. queue的成员函数empty()、size()、front()、back()、push()、pop()的时间复杂度均为O(1)。
  5. 使用front()和back()方法获取队头和队尾元素的引用时,需要先判断队列是否为空,否则会导致程序崩溃。
  6. 在使用自定义类型作为queue的元素时,需要重载运算符<,以便queue可以比较元素大小,从而实现排序。

priority_queue的介绍和使用

⚽priority_queue的介绍

优先队列(Priority Queue)是一种容器适配器,它根据严格的弱排序标准,使得优先队列的第一个元素总是它所包含的元素中最大的。在优先队列中,可以随时插入元素,但只能检索最大元素(优先队列中位于顶部的元素)。

在C++中,优先队列被实现为容器适配器,它可以将特定容器类封装作为其底层容器类,并提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。

底层容器可以是任何标准容器类模板,例如vector和deque,也可以是其他特定设计的容器类。该容器应该可以通过随机访问迭代器访问,并支持以下操作:

  • empty():检测容器是否为空。
  • size():返回容器中有效元素的个数。
  • front():返回容器中第一个元素的引用。
  • push_back(const T& obj):在容器尾部插入元素obj。
  • pop_back():删除容器尾部元素。

需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。

⚽priority_queue的使用

优先队列(Priority Queue)默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构。因此,priority_queue本质上就是一个堆,可以用于需要使用堆的位置。

默认情况下,priority_queue是大堆(即最大堆),即优先队列中的第一个元素总是最大的。如果需要使用最小堆,可以通过指定比较函数来实现。

priority_queue提供了以下常用操作:

函数 说明
priority_queue() 构造一个空的优先级队列。
priority_queue(first, last) 构造一个空的优先级队列。
empty() 检测优先级队列是否为空,是返回true,否则返回false。
top() 返回优先级队列中最大(最小)元素,即堆顶元素。
push(x) 在优先级队列中插入元素x。
pop() 删除优先级队列中最大(最小)元素,即堆顶元素。

示例代码:

#include 
#include 
using namespace std;

int main() {
    priority_queue<int> pq;
    pq.push(3);
    pq.push(1);
    pq.push(4);
    pq.push(1);
    cout << "堆顶元素:" << pq.top() << endl;  
    pq.pop();
    cout << "删除堆顶元素后,新的堆顶元素:" << pq.top() << endl;  
    return 0;
}

运行结果:

栈、队列、优先级队列详解【c++】_第5张图片

如果需要使用最小堆,可以通过指定比较函数来实现。例如,以下代码演示了如何创建一个最小堆:

#include 
#include 
using namespace std;

int main()
{
    priority_queue<int, vector<int>, greater<int>> minHeap;
    minHeap.push(3);
    minHeap.push(1);
    minHeap.push(4);
    minHeap.push(1);
    cout << "堆顶元素:" << minHeap.top() << endl;
    minHeap.pop();
    cout << "删除堆顶元素后,新的堆顶元素:" << minHeap.top() << endl;
    return 0;
}

运行结果:
栈、队列、优先级队列详解【c++】_第6张图片

以下是使用priority_queue时需要注意的事项:

  1. 使用前需要包含头文件
  2. 默认情况下,priority_queue是最大堆,即最大的元素总是位于队列的最前面。如果需要使用最小堆,可以通过指定比较函数来实现。
  3. priority_queue的底层实现是堆,因此可以用于实现最大堆或最小堆。堆是一种特殊的二叉树,具有以下性质:
  • 堆是一棵完全二叉树。
  • 堆中每个节点的值都大于等于(或小于等于)其子节点的值。

总结

本篇博客对c++的stack,queue和priority_queue的介绍和使用进行了阐述,以上三种容器的使用都十分简单,只需要调用相应的方法即可。需要注意的是,使用这些容器时,需要注意线程安全问题、内存管理问题和异常处理问题。

此外,C++还提供了其他的容器,如vector、list、map等,不同的容器适用于不同的场景,开发者需要根据具体的需求选择合适的容器。

到此为止,如果觉得本篇文章对你有帮助的话就请点一个小小的吧,你的鼓励就是我的动力。

栈、队列、优先级队列详解【c++】_第7张图片

你可能感兴趣的:(C++,c++,开发语言)