一、stack基础知识
1、stack基本操作
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
int main ()
{
stack<int> s; // 创建栈
int sum (0);
s.push(i); // 入栈
while (!s.empty())// 判断栈是否为空
{
sum += s.top(); // 获取栈顶元素
s.pop(); // 移除栈顶元素
}
cout << "total: " << sum << '\n';
return 0;
}
2、补充说明:
(1)empty():如果栈为空,则返回真值。
(2)size():栈的元素个数
(3)push():()内填入要入栈的元素。
(4)pop():使最顶层的元素出栈,没有返回值。
(5)栈没有clear或者erase函数,如果想要清空一个栈,需要循环的调用出栈函数。
二、表达式转换
1、中缀表达式转前缀表达式
(1)算法
(1) 初始化两个栈:运算符栈
S1
和储存中间结果的栈S2
;(2) 从右至左扫描中缀表达式;
(3) 遇到操作数时,将其压入
S2
;(4) 遇到运算符时,比较其与
S1
栈顶运算符的优先级:(4-1) 如果
S1
为空,或栈顶运算符为右括号)
,则直接将此运算符入栈;(4-2) 否则,若优先级比栈顶运算符的较高或相等,也将运算符压入
S1
;(4-3) 否则,将
S1
栈顶的运算符弹出并压入到S2
中,再次转到(4-1)与S1中新的栈顶运算符相比较;(5) 遇到括号时:
(5-1) 如果是右括号
)
,则直接压入S1
;(5-2) 如果是左括号
(
,则依次弹出S1
栈顶的运算符,并压入S2
,直到遇到右括号为止,此时将这一对括号丢弃;(6) 重复步骤(2)至(5),直到表达式的最左边;
(7) 将
S1
中剩余的运算符依次弹出并压入S2
;(8) 依次弹出
S2
中的元素并输出,结果即为中缀表达式对应的前缀表达式。
(ps:来源于educoder平台https://www.educoder.net/tasks/jx3f9z2pvo8r)
运算符优先级根据下表判断:
(2)原码示例(代码一般,仅供参考)
#include <iostream>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
int main(int argc, const char * argv[])
{
string s;
stack<char> s1;
stack<char> s2;
cin >> s;
for ( int i = s.size()-1; i>=0; i--)//从右到左扫描
{
L1:
if(s[i]>='0' && s[i]<='9')
{
s2.push(s[i]);
}
else
{
if(s[i]==')'||s1.empty())
{
s1.push(s[i]);
}
else if(s[i]=='(')
{
while(s1.top()!=')')
{
s2.push(s1.top());
s1.pop();
goto L1;
}
s1.pop();
}
else if(s1.top()=='*' && (s[i]=='-'||s[i]=='+'))
{
s2.push(s1.top());
s1.pop();
goto L1;
}
else if(s1.top()=='('&& (s[i]=='+'||s[i]=='-'||s[i]=='*'))
{
s2.push(s1.top());
s1.pop();
goto L1;
}
else
{
s1.push(s[i]);
}
}
}
while(!s1.empty())
{
s2.push(s1.top());
s1.pop();
}
while(!s2.empty())
{
printf("%c",s2.top());
s2.pop();
}
return 0;
}
二、中缀表达式转后缀表达式
(1)算法
(1) 初始化两个栈:运算符栈
S1
和储存中间结果的栈S2
;(2) 从左至右扫描中缀表达式;
(3) 遇到操作数时,将其压入
S2
;(4) 遇到运算符时,比较其与
S1
栈顶运算符的优先级:(4-1) 如果
S1
为空,或栈顶运算符为左括号(
,则直接将此运算符入栈;(4-2) 否则,若优先级比栈顶运算符的高,也将运算符压入
S1
(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);(4-3) 否则,将
S1
栈顶的运算符弹出并压入到S2
中,再次转到(4-1)与S1
中新的栈顶运算符相比较;(5) 遇到括号时:
(5-1) 如果是左括号
(
,则直接压入S1
;(5-2) 如果是右括号
)
,则依次弹出S1
栈顶的运算符,并压入S2
,直到遇到左括号为止,此时将这一对括号丢弃;(6) 重复步骤(2)至(5),直到表达式的最右边;
(7) 将
S1
中剩余的运算符依次弹出并压入S2
;(8) 依次弹出
S2
中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。
(2) 原码示例(代码一般,仅供参考)
#include <iostream>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
int main(int argc, const char * argv[]) {
string s;
stack<char> s1;
stack<char> s2;
cin >> s;
for ( int i = 0; i<s.size(); i++)// 从左到右扫描
{
L1:
if(s[i]>='0' && s[i]<='9')
{
s2.push(s[i]);
}
else
{
if(s[i]=='('||s1.empty()||s1.top()=='(')
{
s1.push(s[i]);
}
else if(s[i]==')')
{
while(s1.top()!='(')
{
s2.push(s1.top());
s1.pop();
}
s1.pop();
}
else if((s1.top()=='+'||s1.top()=='-') && s[i]=='*')
{
s1.push(s[i]);
}
else
{
s2.push(s1.top());
s1.pop();
goto L1;
}
}
}
while(!s1.empty())
{
s2.push(s1.top());
s1.pop();
}
char a[s2.size()];
int len=s2.size();
for(int i=s2.size()-1;i>=0;i--)// 因为要逆序输出,所以先把栈逆序存在一个数组中
{
a[i] = s2.top();
s2.pop();
}
for(int j=0;j<len;j++)
{
printf("%c",a[j]);
}
return 0;
}
三、表达式求值
1、计算机求解前缀表达式
(1)算法:
例如前缀表达式
- * + 3 4 5 6
:(1) 从右至左扫描,将
6、5、4、3
压入堆栈;(2) 遇到
+
运算符,因此弹出3
和4
(注意3
为栈顶元素,4
为次顶元素),计算出3+4
的值,得7
,再将7
入栈;(3) 接下来是
*
运算符,因此弹出7
和5
,计算出7*5=35
,将35
入栈;(4) 最后是
-
运算符,计算出35-6
的值,即29
,由此得出最终结果。
简而言之,就是从右至左扫描,是数字则压入栈中,是运算符则从栈中抛出两个数字,其中栈顶为前一个运算值,次顶元素为后一个运算值。
(2)代码示例
#include <iostream>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
int main(int argc, const char * argv[])
{
string s;
stack<int> s1;
cin >> s;
int num1,num2;
int res;
for(int i=s.size()-1;i>=0;i--)
{
if(s[i]<='9' && s[i]>='0')
{
s1.push(s[i]-'0');
}
else if(s[i]=='+')
{
num1 = s1.top();
s1.pop();
num2= s1.top();
s1.pop();
res =(num1+num2);
s1.push(res);
}
else if(s[i]=='-')
{
num1 = s1.top();
s1.pop();
num2= s1.top();
s1.pop();
res =(num1-num2);
s1.push(res);
}
else if(s[i]=='*')
{
num1 = s1.top();
s1.pop();
num2= s1.top();
s1.pop();
res =(num1*num2);
s1.push(res);
}
}
return 0;
}
2、 计算机求解后缀表达式
(1)算法
例如后缀表达式
3 4 + 5 * 6 -
:(1) 从左至右扫描,将
3
和4
压入堆栈;(2) 遇到+运算符,因此弹出
4
和3
(注意4
为栈顶元素,3
为次顶元素,注意与前缀表达式做比较),计算出3+4
的值,得7
,再将7
入栈;(3) 将
5
入栈;(4) 接下来是
*
运算符,因此弹出5
和7
,计算出7*5=35
,将35
入栈;(5) 将
6
入栈;(6) 最后是
-
运算符,计算出35-6
的值,即29
,由此得出最终结果。
(2)代码示例
#include <iostream>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
int main(int argc, const char * argv[])
{
string s;
stack<int> s1;
cin >> s;
int num1,num2;
int res;
for(int i=0;i<s.size();i++)
{
if(s[i]<='9' && s[i]>='0')
{
s1.push(s[i]-'0');
}
else if(s[i]=='+')
{
num1 = s1.top();
s1.pop();
num2= s1.top();
s1.pop();
res =(num2+num1);
s1.push(res);
}
else if(s[i]=='-')
{
num1 = s1.top();
s1.pop();
num2= s1.top();
s1.pop();
res =(num2-num1);
s1.push(res);
}
else if(s[i]=='*')
{
num1 = s1.top();
s1.pop();
num2= s1.top();
s1.pop();
res =(num2*num1);
s1.push(res);
}
}
printf("%d",res);
return 0;
}