数据结构学习(二)栈
栈
出栈顺序:由大变小按顺序,由小变大可突变
-
C++指针特性测试
#include <iostream> using namespace std; int main(){ int *p=new int[10]; for(int i=0;i<10;i++){ p[i]=0; } int k=0; *p++=2; //(*p)++=2会报错 cout<<p[-1]<<" "<<p[0]<<endl; //p++后基指针后移一位,下标前移一位 p--; //不做p--delete会出问题 delete [] p; return 0; }
*p++=2
相当于先*p=2
再p++
,注意不是(*p)++
的效果,这是因为C++中++
的优先级高于*
,先p++
在*p
,由于p++
先返回p
,所以会出现以上效果。(*p)++=2
会报错,左侧使用了++
运算符,已不是一个可赋值的左值。
ADT
const int MAXLISTSIZE = 100;
template<class ElemType>
class SqStack{
private:
ElemType *base; // 栈底指针
ElemType *top; // 栈顶指针
int maxSize; // 允许的最大存储容量(以sizeof(ElemType)为单位
public:
//初始化顺序栈
SqStack(int ms = MAXLISTSIZE):maxSize(ms){
top=new ElemType[ms];
base=top;
};
//删除顺序栈
~SqStack(){StackDestroy();}
//将顺序栈置为空表
bool StackClear(){
if(top==base) return 0; //健壮性设置
top=base;
return 1;
};
//返回顺序栈的长度
int StackLength() const {return top - base;}
//设置顺序栈的长度,不怎么实用
//bool SetListLength(int len);
//判断顺序栈是否为空栈
bool StackisEmpty() const{ return top == base; }
//判断顺序栈是否为满栈
bool StackFull() const{
return top-base==maxSize;
};
//用e返回栈顶元素
bool GetTop(ElemType &e) const{ //通过传入形参获取值,返回值标记是否获取成功
if(top==base) return 0;
e=*(top-1);
return 1;
};
//入栈
bool push(ElemType e){
if(top-base>=maxSize) return 0;
*top++=e; //效果相当于先*top赋值,再top加一
return 1;
};
//出栈
bool pop(ElemType &e){
if(top==base) return 0;
e=*--top;
return 1;
};
//销毁顺序栈
bool StackDestroy(){
if(!base)
return 0;
delete[] base; //起初是没加[],用于基础数据类型时没有区别,但用于对象类型就有区别了。
top=base=NULL;
return 1;
};
//遍历顺序栈
void StackTraverse() const{
ElemType *p=top;
while(p!=base){ //以此为判断标准则p必须模拟栈顶指针
cout<<*(p-1); //栈顶值在指针下面
p--; //别忘了迭代
}
return;
};
//栈空间加倍
bool DoubleSpace(){ maxSize=2*maxSize;return 1; };
ElemType getElem(int n) const{ return *(base+n); } //从栈底到栈顶按下标获取元素
};
函数(使用ADT)
逆置输出
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
// ADT..
template<class ElemType>
void Invert_Input( SqStack<ElemType> &S ){
string str;
getline(cin,str);
int k=str.length();
for(int i=0;i<k;i++){
S.push(str[i]);
}
return ;
};
int main(){
SqStack<char> stc;
Invert_Input(stc);
stc.StackTraverse();
return 0;
}
进制转换
输入十进制非负数与进制数,输出转换后的结果,字母为大写
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
// ADT
/*
bool push(ElemType &e){ <!-1
if(top-base>=maxSize) return 0;
*top++=e;
return 1;
};
*/
template<class ElemType>
void Conversion(SqStack<ElemType> &S, int data, int format){
while(data){
int k=data%format;
char c[2]={char(55+k),char(48+k)}; //<!-1
if(k>=10) S.push(c[0]);
else S.push(c[1]);
data/=format; //别忘了迭代!
}
return ;
};
int main(){
int a,b;
cin>>a>>b;
SqStack<char> stc;
Conversion<char>(stc,a,b);
stc.StackTraverse();
return 0;
}
-
<!-1
此处若将push函数中的形参采取引用形式,则在传入参数时不能直接传入值,只能传入相应变量,否则会出现报错:cannot bind non-const lvalue reference of type 'char&' to an rvalue of type 'char'
显然这里push函数可以不带引号,因此问题不大。
括弧匹配检验
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
//ADT
template<class ElemType>
bool Matching( SqStack<ElemType> &S ){
string str;
getline(cin,str);
int k=str.length();
for(int i=0;i<k;i++){
switch(str[i]){
case '(':{
S.push(str[i]);
break;
}
case ')':{
char c;
S.GetTop(c); //<!-1
// cout<<" c="<<c;
if(c=='('){
S.pop(c);
} else return 0;
break;
}
case '[':{
S.push(str[i]);
break;
}
case ']':{
char c;
S.GetTop(c);
if(c=='['){ //检测是否闭合
S.pop(c); //闭合了则取出
} else return 0; //不闭合则必定出错
}
}
}
if(S.StackisEmpty()) return 1; //栈中无多余括号
else return 0;
};
int main(){
SqStack<char> stc;
if(Matching(stc)) cout<<"Correct";
else cout<<"Wrong";
return 0;
}
<!-1
不必加上判定if(S.GetTop(c))
再执行内部语句,因为当栈内本就为空时会返回false,而此时仍可能出现括号不匹配的情况,也就是无论执行是否成功都要判断。事实上,如果加上了却没意识到这点,可能会导致找不出BUG。
中缀式转换后缀式
一开始想的很麻烦,打算给数字入两次栈反转顺序,后来发现这样不仅麻烦还处理不了符号,所以就去搜了搜,发现思路不是这样的,其实很简单,碰到数字就输出,判断符号优先级,符合要求就输出符号即可,这里我用矩阵表示符号优先级问题:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0}; //operatorPriority
//运算符顺序:'+','-','*','/','(',')','#' 1表示大于,0等于,-1小于,2非法
/*
+ - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =
注意这是运算符与其后运算符的优先级比较
*/
bool isoperator( char op){ //运算符辨识
switch(op){
case '+':return 1;
case '-':return 1;
case '*':return 1;
case '/':return 1;
case '(':return 1;
case ')':return 1;
case '#':return 1;
default:return 0;
}
}
int op2Int(char c){ //运算符转对应矩阵编号,-1表示异常
if(!isoperator(c)) return -1;
switch(c){
case '+':return 0;
case '-':return 1;
case '*':return 2;
case '/':return 3;
case '(':return 4;
case ')':return 5;
case '#':return 6;
}
return -1;
}
template<class ElemType>
void infix_to_suffix( SqStack<ElemType> &S, string &infix, string &suffix){
string number;
S.push('#'); //忘了push导致读取不到
infix=infix+'#';
int k=infix.length(); //放在+'#'之后!
for(int i=0;i<k;i++){
if(isoperator(infix[i])){
// cout<<"!! ";
if(number!=""){
if(suffix!="") suffix=suffix+" "; //规范格式
suffix=suffix+number; //直接输出数字,注意是suffix+string
// cout<<suffix<<endl;
number="";
}
while(1){
char c;
S.GetTop(c); //获取栈顶元素
int k2=op2Int(infix[i]),k1=op2Int(c);
// cout<<infix[i]<<":"<<k2<<" "<<c<<":"<<k1<<" "<<opp[k1][k2]<<endl;
if(opp[k1][k2]==1){
S.pop(c);
if(suffix!="") suffix=suffix+" ";
suffix=suffix+c;
} else
if(opp[k1][k2]==0){ //界限符相抵
S.pop(c);
break;
} else {
S.push(infix[i]);
break;
}
}
} else {
number=number+infix[i];
}
}
};
int main(){
string str,sufstr;
SqStack<char> tmp; //存运算符
getline(cin,str);
infix_to_suffix(tmp,str,sufstr);
cout<<sufstr;
return 0;
}
写的时候犯了蛮多错,比如 suffix=suffix+number
漏掉suffix自己,初始没有将'#'入栈,+'#'
之前就取了infix的长度。格式化因为有suffix的存在,可以直接检测是否为空来判断前置空格。
string2Int
本题没用上,留个档:
int string2Int(string s){ //string转int
int n=0,k=s.length();
for(int i=0;i<k;i++){
n=n*10+int(s[i]-48);
}
return n;
}
参考:[
]
利用后缀式计算中缀式
输入一串中缀式,输出后缀式以及计算结果,操作数为int,结果为double:
const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0}; //operatorPriority
//运算符顺序:'+','-','*','/','(',')','#' 1表示大于,0等于,-1小于,2非法
/*
+ - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =
注意这是运算符与其后运算符的优先级比较
*/
int string2Int(string s){ //string转int
int n=0,k=s.length();
for(int i=0;i<k;i++){
n=n*10+int(s[i]-48);
}
return n;
}
bool isoperator( char op){ //运算符辨识
switch(op){
case '+':return 1;
case '-':return 1;
case '*':return 1;
case '/':return 1;
case '(':return 1;
case ')':return 1;
case '#':return 1;
default:return 0;
}
}
double opCalc(double a,double b,char c){ //计算
if(!isoperator(c)) return 0; //非法运算符返回0
switch(c){
case '+':{
return a+b;
}
case '-':{
return a-b;
}
case '*':{
return a*b;
}
case '/':{
return a/b;
}
}
return 0;
}
int op2Int(char c){ //运算符转对应矩阵编号,-1表示异常
if(!isoperator(c)) return -1;
switch(c){
case '+':return 0;
case '-':return 1;
case '*':return 2;
case '/':return 3;
case '(':return 4;
case ')':return 5;
case '#':return 6;
}
return -1;
}
template<class ElemType>
double calc_suffix( SqStack<ElemType> &S, string &suffix ){
SqStack<char> optr; //存储运算符
string str;
getline(cin,str); //输入中缀式
str=str+" #"; //只设计在空格读取数字,所以需要添加空格
optr.push('#');
int k=str.length(); //中缀式长度
string number; //提取数字
for(int i=0;i<k;i++){
if(isoperator(str[i])){
int k1,k2=op2Int(str[i]);
while(1){
char c;
optr.GetTop(c);
k1=op2Int(c);
// cout<<"c="<<c<<endl;
if(opp[k1][k2]==1){
optr.pop(c);
if(suffix!="") suffix=suffix+" "; //规范输出空格
suffix=suffix+c; //存储中缀表达式
double a,b;
S.pop(a);
S.pop(b); //b在前a在后
b=opCalc(b,a,c);
S.push(b);
} else
if(opp[k1][k2]==0){
optr.pop(c);
break;
} else {
optr.push(str[i]); //推入的是遍历的内容! <!-1
break;
}
}
} else
if(str[i]==' '){ //题目中输入的中缀式以空格分开,所以用空格标记数字的读取
if(number!=""){
S.push(string2Int(number));
if(suffix!="") suffix=suffix+" ";
suffix=suffix+number;
number="";
}
}
else number=number+str[i];
}
double tmp;
S.pop(tmp);
return tmp;
};
int main(){
string suf;
SqStack<double> opnd; //存中间量
double tmp=calc_suffix(opnd,suf);
cout<<suf<<endl<<endl;
cout<<tmp;
return 0;
}
<!-1
犯错两次,每次都推入栈顶符号导致BUG出现..
火车调度
这题不难,但是让我发现了一个指针动态数组的问题:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
/*ADT
//构造函数
SqStack(int ms = MAXLISTSIZE):maxSize(ms){
top=new ElemType[ms];
base=top;
// cout<<"base:"<<base<<endl;
};
//出栈
bool pop(ElemType &e){
if(top==base) return 0;
e=*--top;
// cout<<"&e="<<&e<<endl;
return 1;
};
//销毁顺序栈
bool StackDestroy(){
if(!base)
return 0;
// cout<<*(base+1)<<" base:"<<base;
delete []base; //?加个[]就行了? <!-1
top=base=NULL;
return 1;
};
*/
template<class ElemType>
string Conversion(SqStack<ElemType> &S, string &train){
stringstream ss(train);
string tmp,ord;
while(ss>>tmp){
if(tmp[0]=='H'){
S.push(tmp);
} else {
if(ord!="") ord=ord+" ";
ord=ord+tmp;
}
}
// cout<<"how much:"<<S.StackLength()<<endl;
while(!S.StackisEmpty()){
S.pop(tmp);
if(ord!="") ord=ord+" ";
ord=ord+tmp;
}
return ord;
};
int main(){
string tr,res;
getline(cin,tr);
SqStack<string> stc(40);
res=Conversion(stc,tr);
cout<<res<<" ";
// cout<<endl<<stc.StackisEmpty()<<endl<<sizeof(string)<<endl;
return 0;
}
- string的大小:32字节(大的离谱,我一直以为是不规则的大小)
<!-1
这个地方delete不加[]
会一直报错"Unkonwn Signal",起初以为是指针指向出了问题,输出指针地址后发现一切正常,但它就是报错。后来发现是delete base
语句的问题,早该想到这里是数组,必须要加上[],所以之前一直犯了这个错,但奇怪的是只有使用string的时候暴露了这个问题,所以我去了解了一下有无[]的区别,得出的结论是有[]用于数组,无[]用于非数组,[]的存在会调用数组部分所有的析构函数,而无[]只会调用首个的析构函数。
参考:[
]
迷宫问题
矩形迷宫寻路问题:
//ADT
const int dir[4][2]={0,1,1,0,0,-1,-1,0}; //东南西北顺序
struct node{
int x;
int y;
int ord;
node(){}; //自行构建构造函数后默认构造函数不作数
node(int a,int b,int c):x(a),y(b),ord(c){};
};
//遍历输出
void Traverse(SqStack<node> const &S){
int k=S.StackLength();
for(int i=0;i<k;i++){
if(i) cout<<"->";
if(i && !(i%4)) cout<<endl;
node tmp=S.getElem(i);
cout<<"("<<tmp.x-1<<","<<tmp.y-1<<")";
}
return;
};
bool InputMaze(int row, int col, vector< vector<int> > &maze){ //别忘了数组的引用!
for(int i=1;i<=row;i++){
for(int j=1;j<=col;j++){
cin>>maze[i][j];
}
}
return 1;
}
template<class ElemType>
void maze_path( SqStack<ElemType> &S, int row, int col, node enter, node outer, vector< vector<int> > maze ){
int x=enter.x+1, y=enter.y+1, ord=-1; //入口坐标需要处理
// cout<<x<<","<<y;
maze[x][y]=1;
bool f=1;
int i;
while(f){
// cout<<"1:"<<x<<","<<y<<endl;
// cin>>x; //手动断点
for(i=ord+1;i<4;i++){
int xx=x+dir[i][0],yy=y+dir[i][1]; //逐一遍历方向
// cout<<"2:"<<xx<<","<<yy<<"="<<maze[xx][yy]<<endl;
// cin>>x;
if(!maze[xx][yy]){
node nd(x,y,i);
S.push(nd);
maze[xx][yy]=2; //遍历过的结点标记为2,此处深搜不做回退
x=xx;
y=yy;
ord=-1; //进入新的结点,ord置-1
// cout<<"3:"<<x<<","<<y<<endl;
// cin>>x;
break;
}
}
if(x==outer.x+1 && y==outer.y+1){ //找到出口
S.push(node(x,y,ord)); //推入最后一个结点
break;
}
if(x==enter.x+1 && y==enter.y+1) f=0; //如果起点终点同一点,则语句顺序很重要
if(i==4){
node tmp;
S.pop(tmp);
x=tmp.x;
y=tmp.y;
ord=tmp.ord;
// cout<<"4:"<<x<<","<<y<<endl;
// cin>>x;
}
}
if(f){ //找到出口
Traverse(S);
} else {
cout<<"No Path";
}
return ;
}
int main(){
SqStack<node> stc;
int row,col;
cin>>row>>col;
vector< vector<int> > maze(row+2,vector<int>(col+2,1));
node beg,end;
cin>>beg.x>>beg.y;
cin>>end.x>>end.y;
InputMaze(row,col,maze);
// for(int i=0;i<=row+1;i++){ //检查输入是否成功
// for(int j=0;j<=col+1;j++){
// cout<<maze[i][j]<<" ";
// }
// cout<<endl;
// }
maze_path(stc,row,col,beg,end,maze);
return 0;
}
总结一下:
先说犯的错误,一是输入用函数打包,但传入参数时未引用导致输入失败;二是ord在进入新的结点时未置-1导致方向遍历不完全,这里若是合理调整了退出语句与处理语句的顺序本来可以较容易看出来的。
再说说收获,我发现手动断点可以用输入语句替代,中间量输出标记与值,达到一个良好的调试效果。
回文判断
判断一串以&为分隔符,以@为结束符的字符串是否为回文:
template<class ElemType>
bool parlindrome_judge( SqStack<ElemType> &S ){
string s;
char c;
getline(cin,s,'@'); //规定@为结束符并排除
int i=0,k=s.length();
while(s[i]!='&'){
S.push(s[i]);
i++;
}
i++;
if(k-i!=i-1) return 0;
else {
for(;i<k;i++){
S.pop(c);
if(c!=s[i]) return 0;
}
}
return 1;
}
int main(){
SqStack<char> stc;
if(parlindrome_judge(stc)) cout<<"true";
else cout<<"false";
return 0;
}
中后缀转换四则运算
跟之前的不同之处在于可以忽略输入中的空格并把处理后的中缀式与结果输出:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
//ADT
const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0}; //operatorPriority
//运算符顺序:'+','-','*','/','(',')','#' 1表示大于,0等于,-1小于,2非法
/*
+ - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =
注意这是运算符与其后运算符的优先级比较
*/
int string2Int(string s){ //string转int
int n=0,k=s.length();
for(int i=0;i<k;i++){
n=n*10+int(s[i]-48);
}
return n;
}
bool isoperator( char op){ //运算符辨识
switch(op){
case '+':return 1;
case '-':return 1;
case '*':return 1;
case '/':return 1;
case '(':return 1;
case ')':return 1;
case '#':return 1;
default:return 0;
}
}
double opCalc(double a,double b,char c){ //计算
if(!isoperator(c)) return 0; //非法运算符返回0
switch(c){
case '+':{
return a+b;
}
case '-':{
return a-b;
}
case '*':{
return a*b;
}
case '/':{
return a/b;
}
}
return 0;
}
int op2Int(char c){ //运算符转对应矩阵编号,-1表示异常
if(!isoperator(c)) return -1;
switch(c){
case '+':return 0;
case '-':return 1;
case '*':return 2;
case '/':return 3;
case '(':return 4;
case ')':return 5;
case '#':return 6;
}
return -1;
}
template<class ElemType>
double calc_inffix( SqStack<ElemType> &S, string &inffix ){
SqStack<char> optr; //存储运算符
string str;
getline(cin,str); //输入中缀式
str=str+"#";
optr.push('#');
int k=str.length(); //中缀式长度
string number; //提取数字
for(int i=0;i<k;i++){
if(isoperator(str[i])){
if(str[i]!='#')
inffix=inffix+str[i];
if(number!=""){
S.push(string2Int(number));
number="";
}
int k1,k2=op2Int(str[i]);
while(1){
char c;
optr.GetTop(c);
k1=op2Int(c);
// cout<<"c="<<c<<endl;
if(opp[k1][k2]==1){
optr.pop(c);
double a,b;
S.pop(a);
S.pop(b); //b在前a在后
b=opCalc(b,a,c);
S.push(b);
} else
if(opp[k1][k2]==0){
optr.pop(c);
break;
} else {
optr.push(str[i]);
break;
}
}
} else
if(str[i]==' ') continue;
else {
number=number+str[i];
inffix=inffix+str[i];
}
}
double tmp;
S.pop(tmp);
return tmp;
};
int main(){
string suf;
SqStack<double> opnd; //存中间量
double tmp=calc_inffix(opnd,suf);
cout<<suf<<endl<<endl;
cout<<tmp;
return 0;
}
中缀式转后缀式(排除空格,考虑负数)
考虑了负数并排除了多余的(suoyoude)空格:
const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0}; //operatorPriority
//运算符顺序:'+','-','*','/','(',')','#' 1表示大于,0等于,-1小于,2非法
/*
+ - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =
注意这是运算符与其后运算符的优先级比较
*/
bool isoperator( char op){ //运算符辨识
switch(op){
case '+':return 1;
case '-':return 1;
case '*':return 1;
case '/':return 1;
case '(':return 1;
case ')':return 1;
case '#':return 1;
default:return 0;
}
}
int op2Int(char c){ //运算符转对应矩阵编号,-1表示异常
if(!isoperator(c)) return -1;
switch(c){
case '+':return 0;
case '-':return 1;
case '*':return 2;
case '/':return 3;
case '(':return 4;
case ')':return 5;
case '#':return 6;
}
return -1;
}
template<class ElemType>
void infix_to_suffix( SqStack<ElemType> &S, string &infix, string &suffix){
string number;
S.push('#'); //忘了push导致读取不到
infix=infix+'#';
int k=infix.length(); //放在+'#'之后!
for(int i=0;i<k;i++){
if(isoperator(infix[i])){
// cout<<"!! ";
if(number!=""){
if(suffix!="") suffix=suffix+" "; //规范格式
suffix=suffix+number; //直接输出数字,注意是suffix+string
// cout<<suffix<<endl;
number="";
} else {
if(infix[i]=='-'){
number=number+infix[i];
continue;
}
}
while(1){
char c;
S.GetTop(c); //获取栈顶元素
int k2=op2Int(infix[i]),k1=op2Int(c);
// cout<<infix[i]<<":"<<k2<<" "<<c<<":"<<k1<<" "<<opp[k1][k2]<<endl;
if(opp[k1][k2]==1){
S.pop(c);
if(suffix!="") suffix=suffix+" ";
suffix=suffix+c;
} else
if(opp[k1][k2]==0){ //界限符相抵
S.pop(c);
break;
} else {
S.push(infix[i]);
break;
}
}
} else {
if(infix[i]!=' ')
number=number+infix[i];
}
}
};
int main(){
string str,sufstr;
SqStack<char> tmp; //存运算符
getline(cin,str);
infix_to_suffix(tmp,str,sufstr);
cout<<sufstr;
return 0;
}
简单修改一下 infix_to_suffix()
函数即可。如果 number
为空而又碰到负号意味着负数的出现。
利用后缀式计算中缀式(考虑负数,过滤空格)
const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0}; //operatorPriority
//运算符顺序:'+','-','*','/','(',')','#' 1表示大于,0等于,-1小于,2非法
/*
+ - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =
注意这是运算符与其后运算符的优先级比较
*/
int string2Int(string s){ //string转int,可分辨正负
int f=1;
if(s[0]=='-'){
f=-1;
s.erase(0,1); //去掉负号
}
int n=0,k=s.length();
for(int i=0;i<k;i++){
n=n*10+int(s[i]-48);
}
return n*f;
}
bool isoperator( char op){ //运算符辨识
switch(op){
case '+':return 1;
case '-':return 1;
case '*':return 1;
case '/':return 1;
case '(':return 1;
case ')':return 1;
case '#':return 1;
default:return 0;
}
}
double opCalc(double a,double b,char c){ //计算
if(!isoperator(c)) return 0; //非法运算符返回0
switch(c){
case '+':{
return a+b;
}
case '-':{
return a-b;
}
case '*':{
return a*b;
}
case '/':{
return a/b;
}
}
return 0;
}
int op2Int(char c){ //运算符转对应矩阵编号,-1表示异常
if(!isoperator(c)) return -1;
switch(c){
case '+':return 0;
case '-':return 1;
case '*':return 2;
case '/':return 3;
case '(':return 4;
case ')':return 5;
case '#':return 6;
}
return -1;
}
template<class ElemType>
double calc_suffix( SqStack<ElemType> &S, string &suffix ){
SqStack<char> optr; //存储运算符
string str;
getline(cin,str); //输入中缀式
str=str+" #";
optr.push('#');
int k=str.length(); //中缀式长度
string number; //提取数字
for(int i=0;i<k;i++){
if(isoperator(str[i])){
if(number!=""){
S.push(string2Int(number));
if(suffix!="") suffix=suffix+" ";
suffix=suffix+number;
number="";
} else {
if(str[i]=='-'){ //出现负数
number=number+str[i];
continue;
}
}
int k1,k2=op2Int(str[i]);
while(1){
char c;
optr.GetTop(c);
k1=op2Int(c);
// cout<<"c="<<c<<endl;
if(opp[k1][k2]==1){
optr.pop(c);
if(suffix!="") suffix=suffix+" "; //规范输出空格
suffix=suffix+c;
double a,b;
S.pop(a);
S.pop(b); //b在前a在后
b=opCalc(b,a,c);
S.push(b);
} else
if(opp[k1][k2]==0){
optr.pop(c);
break;
} else {
optr.push(str[i]);
break;
}
}
} else
if(str[i]==' ') continue;
else number=number+str[i];
}
double tmp;
S.pop(tmp);
return tmp;
};
int main(){
string suf;
SqStack<double> opnd; //存中间量
double tmp=calc_suffix(opnd,suf);
cout<<suf<<endl<<endl;
cout<<tmp;
return 0;
}
同上简单修改取数逻辑即可,更新一下字符串转数字的函数使其能够分辨正负。
奇怪的键盘
给一个字符串,进行递归的消消乐,两两相同一起消除:
//遍历输出
void Traverse(SqStack<char> const &S){
int k=S.StackLength();
for(int i=0;i<k;i++){
cout<<S.getElem(i);
}
return;
};
template<class ElemType>
void noTheSame( SqStack<ElemType> &S ){
string str;
getline(cin,str);
int k=str.length();
for(int i=0;i<k;i++){
if(!i) S.push(str[i]);
else{
char c;
S.GetTop(c);
if(c!=str[i]) S.push(str[i]); //别老是push你那c啊喂!
else S.pop(c);
}
// Traverse(S);
// cout<<endl;
}
return;
}
int main(){
SqStack<char> stc;
noTheSame(stc);
Traverse(stc);
return 0;
}
每次都push(c),每次都De这个BUG,不长记性了属于是。
函数(递归)
求最大值
简单的求序列最大值:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int findMax(int n){
int k;
cin>>k;
if(n==1) return k;
else{
int t=findMax(n-1);
return k>t?k:t;
}
}
int main(){
int n;
cin>>n;
cout<<findMax(n);
return 0;
}
中点优先的顺序遍历顺序表
先遍历一遍顺序表,再取中点,先输出中点,再输出左半段,再输出右半段;每段的输出规则都同上:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
void midOut(int l,int r,vector<int> v){
if(l>r) return; //左端点小于右端点则退出
int m=(l+r)/2;
cout<<v[m]<<" "; //先输出中点
midOut(l,m-1,v); //先左半部分,右端点为m-1
midOut(m+1,r,v); //再右半部分,左端点为m+1
return;
}
int main(){
int n;
cin>>n;
vector<int> v(n);
for(int i=0;i<n;i++){
cin>>v[i];
}
for(int i=0;i<n;i++){
cout<<v[i]<<" "; //先遍历一遍
}
cout<<endl;
midOut(0,n-1,v);
return 0;
}
函数(使用STL)
栈 stack
定义在头文件 <stack>
中,基本用法:
e=stack.top(); //返回栈顶元素
stack.empty(); //判断堆栈是否为空
e=stack.size(); //返回堆栈的大小
stack.pop(); //去除栈顶元素
stack.push(e) //将元素e推入栈
stack <int> s; //创建栈对象
棒球比赛
题目:
输入分数或特定记号'C','D','+',处理分数最终得到总分
示例:
输入:5 2 C D +
输出:30
解释:
"5" - 记录加 5 ,记录现在是 [5]
"2" - 记录加 2 ,记录现在是 [5, 2]
"C" - 使前一次得分的记录无效并将其移除,记录现在是 [5].
"D" - 记录加 2 * 5 = 10 ,记录现在是 [5, 10].
"+" - 记录加 5 + 10 = 15 ,记录现在是 [5, 10, 15].
所有得分的总和 5 + 10 + 15 = 30
代码:
#include <iostream>
#include <string>
#include <stack>
#include <sstream>
#include <vector>
using namespace std;
int string2Int(string s){ //string转int,可分辨正负
int f=1;
if(s[0]=='-'){
f=-1;
s.erase(0,1); //去掉负号
}
int n=0,k=s.length();
for(int i=0;i<k;i++){
n=n*10+int(s[i]-48);
}
return n*f;
}
int calPoints(string s){
stack<int> sta;
stringstream ss(s);
int cnt=0;
while(ss>>s){
int k=s.length();
if(s[0]>='0' && s[0]<='9' || s[0]=='-'){ //如果一位数字
int tmp=string2Int(s);
sta.push(tmp);
} else { //其他记号
switch(s[0]){
case 'C':{
sta.pop();
break;
}
case 'D':{
int tmp=sta.top();
sta.push(tmp*2);
break;
}
case '+':{
int t=sta.top(),t1; //取出栈顶元素
sta.pop();
t1=sta.top(); //取出原栈顶下的元素
t1=t1+t;
sta.push(t); //推入原栈顶
sta.push(t1); //推入新栈顶
}
}
}
}
while(!sta.empty()){ //计算栈内总值
int k=sta.top();
sta.pop();
cnt+=k;
}
return cnt;
}
int main(){
string s;
getline(cin,s);
cout<<calPoints(s);
return 0;
}
比较含退格的字符串
给定两个字符串,其中'#'表示退格,比较退格后的两串是否相等,要求时间复杂度为O(n):
#include <iostream>
#include <string>
#include <stack>
#include <sstream>
#include <vector>
using namespace std;
bool backTheSame(string S,string T){
stack<char> s1,s2;
int k1=S.length(),k2=T.length();
for(int i=0;i<k1;i++){
if(S[i]=='#' && !s1.empty()) s1.pop(); //退格处理,注意空栈不可pop
else s1.push(S[i]);
}
for(int i=0;i<k2;i++){
if(T[i]=='#' && !s2.empty()) s2.pop();
else s2.push(T[i]);
}
if(s1.size()!=s2.size()){ //比较长度
cout<<s1.size()<<" "<<s2.size();
// cout<<"?";
return 0;
}
else{
while(!s1.empty()){ //逐一比较
char c1,c2;
c1=s1.top();
c2=s2.top();
s1.pop();
s2.pop();
if(c1!=c2){
// cout<<"!";
return 0;
}
}
}
return 1;
}
int main(){
string s,t;
getline(cin,s);
getline(cin,t);
bool f=backTheSame(s,t);
if(f) cout<<"true";
else cout<<"false";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具