欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > 数据结构--【栈与队列】笔记

数据结构--【栈与队列】笔记

2025/3/14 1:45:46 来源:https://blog.csdn.net/2401_86190146/article/details/146064419  浏览:    关键词:数据结构--【栈与队列】笔记

栈的应用【实验题】

使用栈实现后缀表达式计算,其中,在后缀表达式中,输入的数字为整数,且为正数,数字、符号之间用空格隔开,整个后缀表达式用“#”表示结束。其中,整个后缀表达式长度不超过200,每个数字位数不超过10。

提示:读取数据的过程中,可以利用栈处理每个数字。

输入样例:

11 2 3 + * #(注:对应的中缀表达式是11*(2+3))

6 2 3 + * 5 / 7 - #(注:对应的中缀表达式是6*(2+3)/5-7)

输出样例:

55

-1

#include<iostream>
#include<string>
using namespace std;
struct stack
{int a[300];int index = -1;void instack(int x)  //入栈操作{a[++index] = x;}void calculate(char k)  //k是运算符{int sum = 0;int k1, k2;k1 = showtop(); outstack();k2 = showtop(); outstack();if (k == '+'){sum = k1 + k2;}else if (k == '-'){sum = k2 - k1;}else if (k == '*'){sum = k1 * k2;}else if (k == '/'){sum = k2 / k1;}instack(sum);}void outstack() //出栈{index--;}int showtop()  //显示栈顶字符{return a[index];}
};
int main()
{stack f;string b;while (cin >> b && b != "#"){if (b == "+" || b == "-" || b == "*" || b == "/"){f.calculate(b[0]);}else{int num = stoi(b);f.instack(num);}}cout << f.showtop() << endl;return 0;
}

整体还是很简单的,主要操作步骤如下

1.写一个栈的结构,这里面设置栈结构(a[]数组),index索引指向目前栈顶,并包含入栈、出栈、显示栈顶字符操作

2.输入字符

3.写运算calculate函数

要注意的问题是cin可以隔断输入的string b,此时比如单个输入的"11"就是要给字符串b

string b;while (cin >> b && b != "#"){if (b == "+" || b == "-" || b == "*" || b == "/"){f.calculate(b[0]);}else{int num = stoi(b);f.instack(num);}}

同时calculate()也可以用switch写,更简洁一些

 void calculate(char k) {int right = a[index--]; // 右操作数(栈顶)int left = a[index--];  // 左操作数(次栈顶)int sum = 0;switch(k) {case '+': sum = left + right; break;case '-': sum = left - right; break;case '*': sum = left * right; break;case '/': sum = left / right; break; // 修正为 left / right}a[++index] = sum; // 结果入栈}

单调栈

这是种特殊的栈结构,其元素按照单调递增或单调递减的顺序排列

普通暴力方法是 O(n²) ,这个可以优化至 O(n)。

典型例题:

P5788 【模板】单调栈 - 洛谷

题目描述

给出项数为 n 的整数数列 a1…n​。

定义函数 f(i) 代表数列中第 i 个元素之后第一个大于 ai​ 的元素的下标,即 f(i)=mini<j≤n,aj​>ai​​{j}。若不存在,则 f(i)=0。

试求出 f(1…n)。

输入格式

第一行一个正整数 n。

第二行 n 个正整数 a1…n​。

输出格式

一行 n 个整数表示 f(1),f(2),…,f(n) 的值。

输入输出样例

输入 

5
1 4 2 3 5

输出 

2 5 4 5 0

说明/提示

【数据规模与约定】

对于 30% 的数据,n≤100;

对于 60% 的数据,n≤5×103 ;

对于 100% 的数据,1≤n≤3×106,1≤ai​≤109。

整体做法就是,用栈来存储索引值,先从前往后遍历数列,遇到第 i 个元素 x ,让它和栈顶元素比较

  • 如果栈顶元素小于它,就把栈顶元素踢出去,索引值 i 成为栈顶,此时栈顶索引对应的那个第一个比它大的索引就是 i 。
  • 如果栈顶元素大于等于它,保存原来栈顶那个元素,把 i 直接加进来。

这样就形成了一个单调递减的栈,遍历每一个元素,后面的元素如果比它前面那个小就会进去待命,反正前面那个大数的结果不是后面那个小数,它只会在遇到比它大的数的时候才会找到答案,此时前面那堆小的答案也是那个新遇到的大数,所以就叽里咕噜全跑出栈来了。

还有一个比较形象的例子,这个题就好像是很多人同时向右看,求看到第一个比自己高的人的那个位置

为什么可以将复杂度降到 O(n)?

我想这是一个一边遍历数组一边比大小的过程,因为在遍历数组的同时本身就形成了一个递减的顺序,所以能够同时遍历数组 + 比大小,高

#include<iostream>
using namespace std;
int res[3000000]; //盛放答案  res[1]的值是第一个大于首元素的元素索引
int st[3000000];  //盛放索引,索引对应的值从大到小排列
int num[3000000]; //盛放原先的数列
int p = 0;  //指针,首元素是1
int main()
{int n,x;cin >> n;for (int i = 1; i <= n; i++){cin >> x;num[i] = x;}for (int i = 1; i <= n; i++){while (p && num[i] > num[st[p]])
//num[st[p]]:表示当前st栈中栈顶元素(索引)对应的那个数值{int j = st[p];  //设一个整数j存索引值p--;res[j] = i;//该索引值第一个比它大的索引是i}p++;st[p] = i;  //不管num[i]是大是小都要入栈}for (int i = 1; i <= n; i++)cout << res[i] << " ";return 0;
}

出栈顺序判断

P4387 【深基15.习9】验证栈序列 - 洛谷

题目描述

给出两个序列 pushed 和 poped 两个序列,其取值从 1 到 n(n≤100000)。已知入栈序列是 pushed,如果出栈序列有可能是 poped,则输出 Yes,否则输出 No。为了防止骗分,每个测试点有多组数据,不超过 5 组。

输入格式

第一行一个整数 q,询问次数。

接下来 q 个询问,对于每个询问:

第一行一个整数 n 表示序列长度;

第二行 n 个整数表示入栈序列;

第三行 n 个整数表示出栈序列;

输出格式

对于每个询问输出答案。

输入输出样例

输入 

2
5
1 2 3 4 5
5 4 3 2 1
4
1 2 3 4
2 4 1 3

输出 

Yes
No

其实是一个模拟出栈过程的题 

#include<iostream>
#include<string.h>
using namespace std;
int push[100000];
int pop[100000];
int q, n;
struct stack 
{int st[100000];int ttop = -1;  //top指向当前栈顶元素void popp() { ttop--; }void pushh(int x) { ttop++; st[ttop] = x; }bool isempty() { return ttop == -1 ? 1 : 0; }int top() { return st[ttop]; }
};
bool check()   //模拟出栈过程
{int cnt = 0;  //表示pop[]的索引stack s;for (int i = 0; i < n; i++){s.pushh(push[i]);  //入栈while (s.top() == pop[cnt])  //当栈顶元素等于pop[cnt]的时候出栈{cnt++;    //pop[]顺便往后移s.popp();   //出栈if (s.isempty())   
//如果出完栈以后栈空了,就直接退出,因为原来那个s.top()不会判断栈有没有空,会出现错误{break;}}}if (s.isempty()) return true;else return false;while (!s.isempty())  //清空栈{s.popp();}}
int main()
{for (cin>>q; q; q--){cin >> n;for (int i = 0; i < n; i++)  cin >> push[i];for (int i = 0; i < n; i++)  cin >> pop[i];if (check()) cout << "Yes" << endl;else cout << "No" << endl;}return 0;
}

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词