Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++栈和队列

C++栈和队列

作者头像
谙忆
发布于 2021-01-19 03:53:04
发布于 2021-01-19 03:53:04
7050
举报
文章被收录于专栏:程序编程之旅程序编程之旅

使用标准库的栈和队列时,先包含相关的头文件

代码语言:javascript
AI代码解释
复制
#include<stack>
#include<queue>

定义栈如下:

代码语言:javascript
AI代码解释
复制
stack<int> stk;

定义队列如下:

代码语言:javascript
AI代码解释
复制
queue<int> q;

栈提供了如下的操作

代码语言:javascript
AI代码解释
复制
s.empty()               如果栈为空返回true,否则返回false  
s.size()                返回栈中元素的个数  
s.pop()                 删除栈顶元素但不返回其值  
s.top()                 返回栈顶的元素,但不删除该元素  
s.push()                在栈顶压入新元素  

队列提供了下面的操作

代码语言:javascript
AI代码解释
复制
q.empty()               如果队列为空返回true,否则返回false  
q.size()                返回队列中元素的个数  
q.pop()                 删除队列首元素但不返回其值  
q.front()               返回队首元素的值,但不删除该元素  
q.push()                在队尾压入新元素  
q.back()                返回队列尾元素的值,但不删除该元素  

c++stack(堆栈)

它是一个容器的改编,它实现了一个先进后出的数据结构(FILO)

使用该容器时需要包含#include头文件;

定义stack对象的示例代码如下:

stacks1;

stacks2;

stack的基本操作有:

1.入栈:如s.push(x);

2.出栈:如 s.pop().注意:出栈操作只是删除栈顶的元素,并不返回该元素。

3.访问栈顶:如s.top();

4.判断栈空:如s.empty().当栈空时返回true。

5.访问栈中的元素个数,如s.size();

下面举一个简单的例子:

代码语言:javascript
AI代码解释
复制
  #include<iostream>  
    #include<stack>  
    using namespace std;  
    int main(void)  
    {  
        stack<double>s;//定义一个栈  
        for(int i=0;i<10;i++)  
            s.push(i);  
        while(!s.empty())  
        {  
            printf("%lf\n",s.top());  
            s.pop();  
        }  
        cout<<"栈内的元素的个数为:"<<s.size()<<endl; 
    }
栈是限定仅在表尾进行插入或删除操作的线性表,
因此表尾端成为栈顶,相应的,表头端成为栈底,不含有任何元素的栈称为空栈。
栈的修改遵循后进先出的原则,因此栈又称为后进先出的线性表,简称LIFO结构。
栈一般采用数组作为其存储结构,这样做可以避免使用指针,简化程序
,当然数组需要预先声明静态数据区的大小,但这不是问题,因为即便是频繁进出入栈操作,
任何时刻栈元素的实际个数也不会很多,为栈预留一个足够大但又不占用太多空间并不是很困难,
如果不能做到这一点,那么节省内存的方法就是使用链表存储栈。

线性表实现栈的基本操作
    #include<iostream>  
    #include<cstdio>  
    using namespace std;  
    typedef struct Stacknode//定义链式栈的结构体  
    {  
        int data;//数据域  
        Stacknode *next;//下一节点的指针域  
    }Stacknode,*Stack;  
    //初始化一个链式栈(返回一个链式栈的头节点)  
    Stack InitStack()  
    {  
        Stack stack=(Stack)malloc(sizeof(Stacknode));  
        stack->next=NULL;  
        return stack;  
    }  
    //入栈  
    void Push(Stack stack,int newData)  
    {  
        //判断是否为空  
        if(stack==NULL)  
        {  
            printf("栈未初始化,请初始化以后再使用\n");  
            return;  
        }  
        //找到最后一个节点  
       Stacknode *lastnode=stack;  
       while(lastnode->next)  
        {  
        lastnode=lastnode->next;  
        }  
       lastnode->next=(Stacknode*)malloc(sizeof(Stacknode*));  
       lastnode->next->data=newData;  
       lastnode->next->next=NULL;  
       printf("入栈成功!\n");  
    }  
    //出栈  
    int Pop(Stack stack)  
    {  
        //判断栈是否为空  
        if(!stack->next)  
        {  
            printf("栈为空,无法出栈\n");  
            return -1;//-1只是一个自定义的错误代码  
        }  
        //找到最后一个节点的钱一个节点  
        //tempNode:最后一个节点的前一个节点  
        Stacknode *tempNode=stack;  
        while(tempNode->next->next)  
        {  
            tempNode=tempNode->next;  
        }  
        int data=tempNode->next->data;  
        free(tempNode->next);  
        tempNode->next=NULL;  
        return data;  
    }  

    int main()  
    {  
        Stack stack=InitStack();  
        Push(stack,3);//3进栈  
        Push(stack,4);//4进栈  
        Push(stack,5);//5进栈  
        printf("%d\n",Pop(stack));  
        printf("%d\n",Pop(stack));  
        printf("%d\n",Pop(stack));  
        printf("%d\n",Pop(stack));//第4次出栈,应该出错  
        return 0;  
    }  
queue模版类的定义在<queue>头文件中。
queue与stack模版非常类似,queue模版也需要定义两个模版参数,
一个是元素类型,一个是容器类型,元素类型是必要的,
容器类型是可选的,默认为dqueue类型。

定义queue对象的示例代码如下:
queue<int>q1;
queue<double>q2;
queue的基本操作有:
1.入队:如q.push(x):将x元素接到队列的末端;
2.出队:如q.pop() 弹出队列的第一个元素,并不会返回元素的值;
3,访问队首元素:如q.front()
4,访问队尾元素,如q.back();
5,访问队中的元素个数,如q.size();.优先队列
在<queue>头文件中,还定义了一个非常有用的模版类priority_queue
(优先队列),优先队列与队列的差别在于优先队列不是按照入队的顺序出队,
而是按照队列中元素的优先权顺序出队(默认为大者优先,也可以通过指定算子来指定自己的优先顺序)默认是一个大根堆。
priority_queue模版类有三个模版参数,元素类型,容器类型,比较算子。
其中后两个都可以省略,默认容器为vector,默认算子为less,即小的往前排,大的往后排(出队时序列尾的元素出队)。

定义priority_queue对象的示例代码如下:
priority_queue<int>q1;
priority_queue<pair<int,int> >q2;
priority_queue<int,vector<int>,greater<int> >q3;
//定义小的先出队
priority_queue的基本操作均与queue相同
初学者在使用priority_queue时,最困难的可能就是如何定义比较算子了。
如果是基本数据类型,或已定义了比较运算符的类,可以直接用STL的less算子和greater算子——默认为使用less算子,
即小的往前排,大的先出队。如果要定义自己的比较算子,方法有多种,
这里介绍其中的一种:重载比较运算符。优先队列试图将两个元素x和y代入比较运算符
(对less算子,调用x<y,对greater算子,调用x>y),若结果为真,则x排在y前面,y将先于x出队,反之,则将y排在x前面,x将先出队。

看下面这个简单的示例:
    #include<iostream>  
    #include<queue>  
    #include<stdlib.h>  
    using namespace std;  
    class T  
    {  
    public:  
        int x,y,z;  
        T(int a,int b,int c):x(a),y(b),z(c)  
        {  
        }  
    };  
    bool operator<(const T&t1,const T&t2)  
    {  
        return t1.z<t2.z; int="" t="">q;  
        q.push(T(4,4,3));  
        q.push(T(2,2,5));  
        q.push(T(1,5,4));  
        q.push(T(3,3,6));  
        while(!q.empty())  
        {  
            T t=q.top();  
            q.pop();  
            cout<<t.x<<endl;  
        }
     }

栈的应用

①数制转换:

将一个非负的十进制整数N转换为另一个等价的基为B的B进制数的问题,很容易通过”除B取余法”来解决。

【例】将十进制数13转化为二进制数。 解答:按除2取余法,得到的余数依次是1、0、1、1,则十进制数转化为二进制数为1101。 分析:由于最先得到的余数是转化结果的最低位,最后得到的余数是转化结果的最高位,因此很容易用栈来解决。

具体算法如下:

代码语言:javascript
AI代码解释
复制
#include <STACK>    //C++中使用栈要包含的头文件
using namespace std;//这个也是要加的

void conversion(int N,int B)
{//假设N是非负的十进制整数,输出等值的B进制数

  stack<int> S;        //创建一个元素类型为int型的空栈
  while(N)
  {
    S.push(N%B); //将转换后的数值,从底位到高位开始入栈
    N=N/B;
  }
  while(!S.empty())//栈非空时退栈输出
  {
    printf("%d",S.top());    //打印栈顶元素
    S.pop();    //将栈顶元素出栈
  }
}

int main()
{
  conversion(10,2);
}

②表达式求值

表达式求值是程序设计语言编译中的一个最基本的问题。我们讨论一种简单直观的方法“算法优先级法”

算术四则运算的规则:

1、从左到右

2、先乘除后加减

3、先括号内,后括号外 【例】4 + 2*3 -10/5 每一步的计算顺序应该是:

4 + 2*3 -10/5 = 4 + 6 - 10/5 = 10 - 10/5 = 10 - 2 = 8

算法步骤:(我们假设表达式以字符‘#’结尾)

(1)首先,创建空运算符栈OPTR,将表达式起始符‘#’压入栈底,创建空操作数栈OPND

(2)依次读入表达式中的每个字符,若是操作数则进操作数栈,若是运算符则和运算符栈顶的运算符比较优先级后,做如下相应操作:

1.如果栈顶的运算符优先级较低,则把新的运算符压入OPTR;执行(2)

2.如果栈顶的运算符优先级较高,则将其 和 操作数栈的两个栈顶元素 退栈,计算3个元素组成的表达式的值,再压入操作数栈,然后继续判断;

3.如果栈顶的运算符优先级相等(除了#符外,只有‘(’和‘)’是相等的),则将‘(’出栈;执行(2)

(3)直到整个表达式求值完毕(即OPTR栈顶元素和当前读入的字符均为‘#’)

具体算法实现:

代码语言:javascript
AI代码解释
复制
#include <iostream>   
#include <stack>//C++中使用栈要包含的头文件

using namespace std;

//符号数组   
char symbol[7] = {'+', '-', '*', '/', '(', ')', '#'};  

//栈内元素的优先级   
int in[7] = {3, 3, 5, 5, 1, 6, 0};  

//栈外元素的优先级   
int out[7] = {2, 2, 4, 4, 6, 1, 0};  

/* 
 * 通过符号字符获取它的数组下标 
 */ 
int get(char c)  
{  
  switch(c)  
  {  
  case '+':  
    return 0;  
  case '-':  
    return 1;  
  case '*':  
    return 2;  
  case  '/':  
    return 3;  
  case '(':  
    return 4;  
  case ')':  
    return 5;  
  case '#':  
    return 6;  
  default:   
    return 6;  
  }  
}  

/* 
 * 比较栈内运算符c1和栈外运算符c2的优先级 
 */ 
char precede(char c1, char c2)  
{  
  int i1 = get(c1);  
  int i2 = get(c2);  

  if(in[i1] > out[i2])  
  {  
    return '>';  
  }  
  else if(in[i1] < out[i2])  
  {  
    return '<';  
  }  
  else 
  {  
    return '=';  
  }  
}  

/* 
 * 计算基本表达式的值 
 */ 
int figure(int a, int theta, int b)  
{  
  switch(theta)  
  {  
  case 0:  
    return a + b;  
  case 1:  
    return a - b;  
  case 2:  
    return a * b;  
  default:  
    return a / b;  
  }  
}  

/* 
 * 计算表达式的值 
 */ 
int EvaluateExpression(const char *exp)  
{  
  stack<int> OPND; //操作数栈   
  stack<int> OPTR; //运算符栈   
  OPTR.push(get('#'));

  int flag = 1; //表示正负号 1,表示正 0,表示负   
  int a, theta, b;  

  if(!('+' == *exp || '-' == *exp || '(' == *exp || isdigit(*exp)))  
  {//如果不是以'+'、'-'、'('或者数字的其中一个开头,则表达式错误  
    cout << "表达式出错1" << endl;  
    return -1;  
  }  
  if('+' == *exp)  
  {   
    exp++;//指向下一个字符   
  }
  else if('-' == *exp)  
  {  
    flag = 0;  
    exp++;//指向下一个字符   
  }  

  int index = OPTR.top();                //获取运算符栈顶元素在数组的下标号
  while(*exp || symbol[index] != '#') //如果栈顶元素是'#'且当前元素为空结束计算 
  {  
    if(isdigit(*exp))  
    {//如果当前元素是数字,计算整个操作数的值,然后压入操作数栈
      int sum = 0; 
      while(isdigit(*exp))  
      {//计算操作数的值
        sum = sum * 10 + (*exp - '0');  
        exp++;  
      }
      if (!flag)    //如果是负数
      {
        sum = -sum;
      }
      OPND.push(sum);  
      flag = 1;  
    }  
    else 
    {//如果不是数字
      switch(precede(symbol[OPTR.top()], *exp))//比较栈顶运算符和当前运算符的优先级
      {  
      case '>' :  
        b = OPND.top();
        OPND.pop();
        a = OPND.top();  
        OPND.pop();  
        theta = OPTR.top();  
        OPTR.pop();  
        OPND.push(figure(a, theta, b));  
        break;  
      case '<' :  
        OPTR.push(get(*exp));  
        if(*exp)  
        {  
          exp++;  
        }  
        break;  
      case '=' :  
        OPTR.pop();  
        if(*exp)  
        {  
          exp++;  
        }  
        break;  
      }  
    }
    index = OPTR.top();
  }  
  return OPND.top();  
}  

int main()  
{
  char c[50] = {0};
  cout << "请输入一个表达式: ";
  cin.getline(c,50);
  cout << EvaluateExpression(c) << endl;  

  return 0;  
}

队列的应用

舞伴问题

1、问题叙述 假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。若两队初始人数不相同,则较长的那一队中未配对者,等待下一轮舞曲。现要求写一算法模拟上述舞伴配对问题。 2、问题分析 先入队的男士或女士亦先出队配成舞伴。因此该问题具体有典型的先进先出特性,可用队列作为算法的数据结构。 在算法中,假设男士和女士的记录存放在一个数组中作为输入,然后依次扫描该数组的各元素,并根据性别来决定是进入男队还是女队。当这两个队列构造完成之后,依次将两队当前的队头元素出队来配成舞伴,直至某队列变空为止。此时,若某队仍有等待配对者,算法输出此队列中等待者的人数及排在队头的等待者的名字,他(或她)将是下一轮舞曲开始时第一个可获得舞伴的人。 3、具体算法及相关的类型定义

代码语言:javascript
AI代码解释
复制
#include <queue> 
//C++中使用队列要包含的头文件
using namespace std;
typedef struct
{
  char name[20];
  char sex; //性别,'F'表示女性,'M'表示男性
}Person;

void DancePartner(Person dancer[],int num)
{//结构数组dancer中存放跳舞的男女,num是跳舞的人数。

  Person p;
  queue<Person> Mdancers,Fdancers;

  for(int i = 0; i < num; i++)
  {//依次将跳舞者依其性别入队
    p=dancer[i]; 
    if(p.sex=='F')
      Fdancers.push(p); //排入女队
    else
      Mdancers.push(p); //排入男队
  }
  printf("The dancing partners are: \n \n");
  while(!(Fdancers.empty()||Mdancers.empty()))
  {
    //依次输入男女舞伴名
    p=Fdancers.front();        //获取女队第一人
    Fdancers.pop();            //出队
    printf("%s ",p.name);    //打印出队女士名

    p=Mdancers.front();        //获取男队第一人
    Mdancers.pop();            //出队
    printf("%s\n",p.name);    //打印出队男士名
  }
  if(!Fdancers.empty())
  {//输出女士剩余人数及队头女士的名字
    printf("\n There are %d women waitin for the next round.\n",Fdancers.size());
    p=Fdancers.front(); //取队头
    printf("%s will be the first to get a partner. \n",p.name);
  }
  else if(!Mdancers.empty())
  {//输出男队剩余人数及队头者名字
    printf("\n There are%d men waiting for the next round.\n",Mdancers.size());
    p=Mdancers.front();
    printf("%s will be the first to get a partner.\n",p.name);
  }
  else
  {
    printf("There is not person in the queue!");
  }
}//DancerPartners

int main()
{
  Person p[] = {{"A",'F'},{"B",'F'},{"C",'M'},{"D",'M'}};
  DancePartner(p,4);
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015/08/28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深度学习C++中的数据结构:栈和队列
在C++中,栈和队列是两种非常重要的容器适配器——它们不直接存储数据,而是基于其他基础容器(如vector、list、deque)实现特定的操作逻辑。今天我们就从定义、使用到底层原理,再到实战例题,手把手带你搞懂这两种数据结构。
IFMaxue
2025/08/28
2260
【数据结构】栈和队列-----数据结构中的双生花
栈(Stack)是一种特殊的线性表,其核心特性是只允许在固定一端(栈顶)进行插入和删除操作。这种结构遵循**后进先出(LIFO)**原则:最后进入的元素最先被移除。
凤年徐
2025/08/28
1960
【数据结构】栈和队列-----数据结构中的双生花
【C++数据结构】:栈和队列的奥秘
https://blog.csdn.net/2401_86275172/category_13015951.html
用户11456817
2025/08/28
1350
【C++数据结构】:栈和队列的奥秘
移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——8.stack&&queue&&priority_queue(无习题)
C++ 标准模板库(STL)提供了一系列容器,其中 stack 和 queue 是两种常用的适配器容器。它们基于底层的序列容器(如 vector、deque)实现,分别用于支持栈和队列的操作模型。栈(stack)遵循“后进先出”(LIFO)的原则,而队列(queue)遵循“先进先出”(FIFO)的原则。本文将详细介绍这两种容器的特点、使用方法、实现机制及其应用场景。
hope kc
2024/10/24
3210
C++queue容器学习(详解)
一.queue模版类的定义在<queue>头文件中。 queue与stack模版非常类似,queue模版也需要定义两个模版参数,一个是元素类型,一个是容器类型,元素类型是必要的,容器类型是可选的,默认为dqueue类型。 定义queue对象的示例代码如下: queue<int>q1; queue<double>q2; queue的基本操作有: 1.入队:如q.push(x):将x元素接到队列的末端; 2.出队:如q.pop() 弹出队列的第一个元素,并不会返回元素的值; 3,访问队首元素:如q.front(
Angel_Kitty
2018/04/08
6280
C++queue容器学习(详解)
【C++】STL:栈和队列模拟实现
C++中的stack(栈)和queue(队列)是两种常见的数据结构,用于存储和管理数据。
大耳朵土土垚
2024/06/04
3290
【C++】STL:栈和队列模拟实现
ACM竞赛常用STL(一)
STL 的<utility>头文件中描述了一个看上去非常简单的模板类pair,用来表示一个二元组或元素对,并提供了按照字典序对元素对进行大小比较的比较运算符模板函数。
xindoo
2021/01/22
9790
【C++】开始使用stack 与 queue
送给大家一句话: 忍受现实给予我们的苦难和幸福,无聊和平庸。 – 余华 《活着》
叫我龙翔
2024/04/19
1630
【C++】开始使用stack 与 queue
【C++从小白到大牛】栈和队列(优先级队列)
本文主要讲解C++ STL库中stack、queue、priority_queue的使用方法和模拟实现。
用户11316056
2024/10/16
2410
【C++从小白到大牛】栈和队列(优先级队列)
【程序填空】表达式计算(栈应用)C++
1. Push (OPTR, '#');表示把字符#压入堆栈OPTR中,转换成c++代码就是OPTR.push('#');
叶茂林
2023/07/30
2700
C语言-用栈实现表达式求值(顺序栈)[通俗易懂]
第一种输入方式是直接打出表达式进行整体输入,而第二种则是以一个一个的方式读入,第一种输入方式可以直接建立一个数组char str[ ]然后用gets(str)进行输入,表达式输入非常直观。如果是第二种输入方式则是通过getchar()进行一位位的读取,表达式输入不如第一种直观方便。
全栈程序员站长
2022/07/05
2.1K0
C语言-用栈实现表达式求值(顺序栈)[通俗易懂]
C++13-STL模板
在线练习: http://noi.openjudge.cn/ https://www.luogu.com.cn/
IT从业者张某某
2023/10/16
4440
C++13-STL模板
【C++】基础:STL容器库
STL 容器库是 STL 的一个重要组成部分,提供了多种数据结构,包括序列容器、关联容器和容器适配器等,用于存储和管理数据。容器管理着为其元素分配的存储空间,并提供成员函数来直接访问或通过迭代器(具有类似于指针的属性的对象)访问它们。
DevFrank
2024/07/24
2320
10min快速回顾C++语法(八)STL专题
⭐写在前面的话:本系列文章旨在短时间内回顾C/C++语法中的重点与易错点,巩固算法竞赛与写题过程中常用的语法知识,精准地解决学过但有遗忘的情况,为算法刷题打下坚实的基础。
timerring
2022/09/26
3830
C++ STL容器之priority_queue(优先队列)快速入门
而且可以在任何时候往优先队列里面加入(push)元素,接着优先队列底层的数据结构堆会随时调整结构,使得每次的队首元素都是优先级最大的。(这里的优先级是可以规定出来的,默认是数字越大优先级越大)
可定
2020/04/20
2.6K0
C++的输入输出特点、运算符重载及标准模板库STL
程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入。 注意:cin>>和cin.get()都残留数据不会出错,但是cin.getline会报错,下面的示例中都有体现。
Here_SDUT
2022/06/29
1K0
C++的输入输出特点、运算符重载及标准模板库STL
数据结构:表达式求值
表达式求值是程序设计语言编译的一个最基本问题,其中任何一个表达式都是由操作数、运算符(±*/)、界限符(#,(,),[,] )组成。运算符和界限符统称算符。算符的优先级关系为(数学角度上):
全栈程序员站长
2022/07/02
2990
数据结构:表达式求值
C++(STL3)容器适配器(1) stack<T>,queue<T> and priority_queue<T>
容器适配器是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。 这里有 3 种容器适配器:
种花家的奋斗兔
2020/11/13
8230
C++(STL3)容器适配器(1)   stack<T>,queue<T> and priority_queue<T>
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
前言: 在编程的世界里,数据结构是构建高效、可靠程序的基础。它们就像是我们编程工具箱中的精密工具,帮助我们解决各种复杂的问题。而在C++的STL中,栈(Stack)和队列(Queue)是两种非常重要的数据结构,它们以不同的方式管理和操作数据,为我们的程序提供了极大的灵活性
Eternity._
2024/06/14
5920
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
C++ STL简介
vector 容器是 STL 中最常用的容器之一,vector 实现的是一个动态数组,即可以进行元素的插入和删除。
EmoryHuang
2022/10/28
6010
相关推荐
深度学习C++中的数据结构:栈和队列
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档