栈与队列(ACM)讲解

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

cout << s1.top() << endl;

}
else
cout << "Ignored" << endl;

}
else if(cmd == "FORWARD") //前进操作

{
if(!s2.empty()) //栈2有元素,意味着可以前进

{
s1.push(s2.top()); //把栈2的顶端元素压入栈1
#include <iostream>
using namespace std;
int main()
{

int n, m, i, s=0;

while(cin>>n>>m&&n!=0&&m!=0)

{

s=0;

பைடு நூலகம்
for (i=2; i<=n; i++)

s=(s+m)%i;

cout<<s+1<<endl;
cout << s2.top() << endl;
s2.pop(); //弹出栈2的顶端元素

}
else
cout << "Ignored" << endl;

}
else break;

}
return 0;

}
POJ 3250 :code
栈的经典题目
进制转换的时候每次将所求得的余数压栈。 直到商为0。 按顺序取出来便是正确的转换结果。
s1.push("http://www.acm.org/"); //首页压栈
while(cin >> cmd)

{
if(cmd == "VISIT") //访问操作

{
cin >> url;
s1.push(url); //把访问的地址压入栈1
while(!s2.empty()) s2.pop(); //清空栈2
练习
POJ 3250
给出的序列中,如果i < k < j 而且 h[k] < h[i] < h[j],对i找出i到j 区间比h[i]小的数的个数s[i]。然后对每个i求和。
Web Navigation 在POJ中,一道经典的用到栈的基础题目是Web Navigation[1],
该题目要求模拟出浏览器前进、后退、访问的功能,用栈来表 达最为方便,访问就是压入一个元素进栈,后退就是出栈,而 前进则是把后退出来的元素再按栈的规则弹出。
数制转换
数制转换
标准输入输出
题目描述:
数制转换。(要求采用栈实现,练习进栈入栈函数的编写)
输入: 输入的第一行包含两个数,n,d n表示要转换的数的个数 d表示要转换成的进制数 接下来是n个十进制数

输出: 对每一测试用例,用一行输
输入样例: 2 8 123 213 输出样例: 173 325
B
4 5 A站车厢
x =4
A
3 2
1 Station
模型
x表示A站最前方车厢的编号
y表示依照出栈序列 B站的车厢的序号
a1, a2 ...an下一个需要进入
用栈stack记录当前车站Station中的车厢
初始时,x 0, y a1 , stack为空栈 。
算法
如果 y=0, 那么火车调度成功
• 要求 输入 n 和m, 输出优胜者 • 例如 n = 8 m = 3
一种实现代码如下:
#include<iostream> using namespace std;
struct node{ int num; node *link; };
//结点定义 //人的编号
void initial(node &circle, int n); // 初始化
有一个车站,每天都会有N辆车进站,进站按从1~N的顺序 进站。现在车站的站长想让这些火车按照特定的顺序出站 ,问可以做到吗?
某城市有一个火车站,其中的铁路如图所示 ,车站用来中转车辆。
每辆火车都从A方向驶入车站,再从B方向驶出车站,同时它
的车厢可以进行重新组合。假设火车有n节车厢,分别按顺
否则如果 x = y , 那么让x直接从A开进B

否则如果stack不为空且 y=stack栈顶元素,

stack出栈

否则如果x 0,那么让车厢驶入
stack( 入栈)

否则 输出无解
TOJ 3072
实例
车厢序列
已知车厢的个数N , 给出所有可能的初始序列,使之
能调度到目标序列 1,2...n
开关盒布线判断
对于一个给定的黑箱子开关盒,给定配对的针脚,判断这样的线可 不可以在一个平面的电路板上布下。(不相交)
从某点顺时针开始, 当前元素和栈顶元素可以配对,那么弹出栈顶元素。 当前元素和栈顶元素不能配对,那么将当前元素压栈。 最终栈不空就无解。
回溯深搜的非递归形式
回溯深搜的时候系统就是用栈来实现的。 可以自己模拟一下试试。
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int main()

{
string cmd, url;
stack<string> s1, s2; //定义了两个栈
//栈1用作存储操作队列,而栈2则用作临时保存栈1出栈的数据
的人出圈,接着下一个人又从1开始报数,如此循环,直到只剩最后一个人时,该人即为 胜利者。例如当n=10,k=4时,依次出列的人分别为4、8、2、7、3、10,9、1、6、5, 则5号位置的人为胜利者。给定n个人,请你编程计算出最后胜利者标号数。 输入: 输入包含若干个用例,每个用例为接受键盘输入的两个数n(1<=n<=1000000), k(1<=k<=50),分别表示总人数及报到出圈数。输入为“0 0“表示输入用例结束。 输出: 每个用例用一行输出最后胜利者的标号数。 输入样例1: 11 10 4 00 输出样例1: 1 5
表达式转换
还可以通过树的方式建立表达式树来转换
标准输入输出 题目描述: 小学求算式问题。要求采用栈实现。 输入: 输入第一行为用例个数n。 接下来n个表达式。

输出: 对每一个用例的表达式,输出其结果。 输入样例: 3 2+5 4+2*3-10/5 3*7-2 输出样例: 7 8 19
//想一想,为什么要清空栈2
cout << s1.top() << endl;

}
else if(cmd == "BACK") //返回操作

{
if(s1.size() > 1) //如果此次弹出后不会使得栈变空

{
s2.push(s1.top()); //把栈1顶元素压入栈2
s1.pop();

}

initial(circle, n, m);

solve(circle, n, m);

}
return 0;
}
尾插法建立循环单链表
void initial(node &circle, int n){
circle.num = 1;
// 头结点初始化
circle.link = NULL;
后序表达式求值
后续表达式(逆波兰式)的特点:没有括号。
从前向后扫, 遇到操作数压栈; 遇到操作符,从栈中取出2个操作数运算,结果压栈。 最终栈中所剩的数为结果。
我们先来定义运算符的优先级: ( +,*,/,% 从上到下依次升高
中序表达式求值
中序表达式求值
准备2个栈,一个专门存放运算符,另一个专门存放操作数。 1.遇到),那么退栈计算到(为止.结果压栈。 2.遇到运算数.那么压栈。 3.如果当前运算符优先级低于栈顶运算符.那么计算栈顶运算符并将 结果压栈. 4.否则压栈.

}

return 0;
}
TOJ acm.tju.edu.cn TOJ 1153 TOJ 1547 TOJ 1601 TOJ 3070
线性表
第二讲 数据结构之线性结构
2.栈及其应用
栈的特点
栈具有一个逆序的特点,这便是栈的主要思想。
实例讲解
TOJ1036 ZOJ1259 poj 1363 Rails
栈与队列ACM
第一阶段:基础数据结构
线性结构(顺序表、栈、队列) 非线性结构图(二叉树、平衡二叉树) 排序 查找
第二讲 数据结构之线性结构
1.线性表
约瑟夫问题
• n 个人围成一个圆圈,第1个人从1开始顺时针 报数, 报到m的人,令其出列。然后再从下一 个人开始,从1顺时针报数,报到第m个人,再 令其出列,…,如此下去, 直到圆圈中只剩一 个人为止。此人即为优胜者。
node *r, *s;
r = &circle;
//r始终指向尾结点
for(int i = 2; i <= n; i++){

s = new node; //加入新结点s

s->num = i;

r->link = s; //s将插入r后

r = s; //r指向结点s

}
r->link = &circle; //尾结点指向头结点

r = r->link;
p = r->link;
//找到第m个人p
r->link = p->link;

delete p;
//删除结点
r = r->link;

}
cout << "优胜者是" << r->num <<endl;
}

另一种解法
报数问题 描述: n个人围成一个圈,每个人分别标注为1、2、...、n,要求从1号从1开始报数,报到k
定义优先级: (大于左边所有,小于右边所有 -,+ *,/,%
中序表达式转后序
中序表达式转后序
从左向右, 定义当前运算符now之前运算符last 1.遇到数字直接输出。 2.遇到)就把之前的全部输出。 3.如果now优先级高于last运算符.那么输出now。Last不变。 4.否则输出last。last=now。
void solve(node &circle, int n, int m);

//求解过程

主函数
int main(){
int n, m;
node circle;
while(cin >> n >> m){

if(m == 1){
//特殊处理

cout << n <<endl;

continue;
}
模拟踢人过程
void solve(node &circle, int n, int m){
node *r, *p;
r = &circle;
for(int i = 1; i < n; ++i){ //循环n - 1次

for(int j = 2; j < m; ++j) //记数m - 2次
汉诺塔
三根柱子A,B,C,在A上有从小到大放着一些碟子,碟子在柱子 上只能以小的压在大的上面的形式存在,求如何使这些碟子的顺序 原封不动的转移到另外一跟柱子B上。
汉诺塔拓展
同样是3根柱子和一些盘子,变化的是盘子数是给定的。还是只能 以小压大的方式存在,但目标状态和初始状态的顺序是一样的。
Poj3601
a , a ...a 1,2...n 序编号为
负责车厢调度的工作人员需要知道能否使它以 1 2
n
的顺序从B方向驶出。编写程序,判断是否得到制定的车厢
顺序。
分析
由于火车的调度过程符合“后进先出”的特点,所以本题的 模型是一个栈.可以通过简单模拟来判断火车能否到达目标 状态.
目标序列 5 4 3 2 1 y=1
N=3时,输出
样例
123 132 213 231 321
算法
生成所有 1,2...n的排列,再依次判断是否符合要求。
判断序列是否可行时调用上一题算法。 输出可行解。
N=3时 123 132 213 231 312 321
TOJ 1036 Rails TOJ 1196 Web Navigation /POJ1028 TOJ 3072 Train Order POJ 2082 Terrible Sets 用栈来做O(n)的算法 POJ 1686 Lazy Math Instructor 中序表达式 POJ 3250
出数制转换后的结果
火车车厢重排问题
乱序的车厢在一条铁轨上,压入的车厢不能回到原轨道,希望在狭 窄的空间里将其排成有序的序列。
按顺序扫描车厢, 如果当前的车厢为有序序列的需要车厢,那么参与排队去。 否则,将其压栈,由于车厢在栈内必须有序,所以要找一个可以压 并且栈顶元素与当前车厢序号差小的栈压。 如果没有可以压的栈,那么新开一个栈。 开的栈数为最小用栈数。
相关文档
最新文档