栈的应用
1.括号匹配
在这里我们给出一组带括号的表达式
1.(()))abcd[]{};
2.((()){{bcd}};
3.((]){}[]{{}};
4.()(){}{[]}[];
需要我们去判断里面的括号之间是否匹配
此时可能出现几种情况
1.右括号比左括号多
2.左括号比右括号多
3.括号不匹配
4.括号匹配成功
在这里可以利用栈后进先出的运算方式
将所遇到的左括号入栈,如果碰到右括号,则与栈顶的元素比较。
如果碰到一个 ‘右括号’ 且此时的栈为空,则表明右括号比左括号多。
如果碰到一个’右括号’,但此时与栈顶不相同,则括号不匹配。
字符全部遍历之后,如果栈不为空,则左括号多
如果栈为空,则括号匹配成功。
实现
bool MatchBrackets(char *str)
{
int len = strlen(str);
stack<char> pstr;
for (int i = 0; i < len; i++)
{
if (str[i] == '(' || str[i] == '[' || str[i] == '{') //如果是左括号,则入栈
{
pstr.push(str[i]);
}
else if (str[i] == ')' || str[i] == ']' || str[i] == '}')
{
if (pstr.empty())
{
cout << "右括号比左括号多" << endl;
return false;
}
else
{
if ((str[i] == ')'&&pstr.top() == '(') || (str[i] == ']'&&pstr.top() == '[') || (str[i] == '}'&&pstr.top() == '{'))
{ //左右匹配
pstr.pop();
}
else
{
cout << "括号不匹配" << endl;
return false;
}
}
/*if (pstr.empty())
{
cout << "右括号比左括号多" << endl;
return false;
}*/
}
}
if (!pstr.empty())
{
cout << "左括号比右括号多" << endl;
return false;
}
else
{
cout << "括号匹配" << endl;
return true;
}
}
int main()
{
char *str1 = "(()))abcd[]{}"; //右比左多
char *str2 = "((()){{bcd}}"; //左比右多
char *str3 = "((]){}[]{{}}"; //不匹配
char *str4 = "()(){}{[]}[]"; //匹配
MatchBrackets(str1);
MatchBrackets(str2);
MatchBrackets(str3);
MatchBrackets(str4);
}
实现
bool MatchBrackets(char *str)
{
int len = strlen(str);
stack<char> pstr;
for (int i = 0; i < len; i++)
{
if (str[i] == '(' || str[i] == '[' || str[i] == '{') //如果是左括号,则入栈
{
pstr.push(str[i]);
}
else if (str[i] == ')' || str[i] == ']' || str[i] == '}')
{
if (pstr.empty())
{
cout << "右括号比左括号多" << endl;
return false;
}
else
{
if ((str[i] == ')'&&pstr.top() == '(') || (str[i] == ']'&&pstr.top() == '[') || (str[i] == '}'&&pstr.top() == '{'))
{ //左右匹配
pstr.pop();
}
else
{
cout << "括号不匹配" << endl;
return false;
}
}
/*if (pstr.empty())
{
cout << "右括号比左括号多" << endl;
return false;
}*/
}
}
if (!pstr.empty())
{
cout << "左括号比右括号多" << endl;
return false;
}
else
{
cout << "括号匹配" << endl;
return true;
}
}
缺陷
如果出现了
char *str5 = "))((";
这种形式,本应出现括号不匹配的结果,但是实际输出的是右括号比左括号多的结果。
解决办法:
再添加一个栈,用来保存未能匹配的所有右括号。
在遍历结束之后,将之前的栈和此时添加的栈来进行比较
实现
bool MatchBrackets(char *str)
{
int len = strlen(str);
stack<char> pstr; //左括号栈
stack<char>rightstr; // 未匹配的右括号栈
for (int i = 0; i < len; i++)
{
if (str[i] == '(' || str[i] == '[' || str[i] == '{') //如果是左括号,则入栈
{
pstr.push(str[i]);
}
else if (str[i] == ')' || str[i] == ']' || str[i] == '}')
{
if (pstr.empty()) //碰到右括号 左括号栈为空,则右括号不能匹配 入 未匹配栈
{
rightstr.push(str[i]);
}
else
{
if ((str[i] == ')'&&pstr.top() == '(') || (str[i] == ']'&&pstr.top() == '[') || (str[i] == '}'&&pstr.top() == '{'))
{ //左右匹配
pstr.pop();
}
else //不匹配
{
rightstr.push(str[i]);
}
}
}
}
if (rightstr.empty()&&pstr.empty())
{
cout << "括号匹配" << endl;
return true;
}
else if ( rightstr.empty() && !pstr.empty())
{
cout << "左括号比右括号多" << endl;
return false;
}
else if (!rightstr.empty()&&!pstr.empty())
{
cout << "括号不匹配" << endl;
return false;
}
else if (!rightstr.empty() && pstr.empty())
{
cout << "右括号比左括号多" << endl;
return false;
}
}
测试
int main()
{
char *str1 = "(()))abcd[]{}"; //右比左多
char *str2 = "((()){{bcd}}"; //左比右多
char *str3 = "((]){}[]{{}}"; //不匹配
char *str4 = "()(){}{[]}[]"; //匹配
char *str5 = "))(("; //不匹配
MatchBrackets(str1);
MatchBrackets(str2);
MatchBrackets(str3);
MatchBrackets(str4);
MatchBrackets(str5);
}
2.逆波兰表达式
我们表述一个加法算式通常是 X+Y ,即“操作数1+操作数2”
而逆波兰表达式则为 X Y +
所有的算式都可以用逆波兰表达式写出来
因为操作数在操作符前面的特点,我们可以遍历整个表达式,遇到操作数时,进栈操作数,遇到操作符时,让操作数出栈并进行运算,再将运算结果入栈。
假设此时给的时一个字符串数组
char *str[] = { "12","3","4","+","*","6","-","8","2","/","+" }
我们可以先将整个字符串数组依次压入栈中,随后进行操作
int CalcRPN(char** pstr, int size)
{
stack<int> num;
for (int i = 0; i < size; i++)
{
if (*pstr[i] == '+' || *pstr[i] == '-' || *pstr[i] == '*' || *pstr[i] == '/' || *pstr[i] == '%')
{
int right = num.top(); //先取的是右操作数
num.pop();
int left = num.top(); //后取左操作数
num.pop();
if (*pstr[i] == '+')
num.push(left + right);
else if (*pstr[i] == '-')
num.push(left - right);
else if (*pstr[i] == '*')
num.push(left * right);
else if (*pstr[i] == '/')
{
if (right == 0)
{
perror("除数为0");
exit(EXIT_FAILURE);
}
else
num.push(left / right);
}
else if (*pstr[i] == '%')
num.push(left % right);
else
{
cout << "非法表达式" << endl;
exit(EXIT_FAILURE);
}
}
else
{
num.push(atoi(pstr[i]));
}
}
return num.top();
}
int main()
{
char *str[] = { "12","3","4","+","*","6","-","8","2","/","+" };
int sz = sizeof(str) / sizeof(str[0]);
stack<char*>pstr;
for (int i = 0; i < sz; i++)
{
pstr.push(str[i]);
}
cout << CalcRPN(str, sz) << endl;
但是通常我们输入一个算式通常是一个中缀表达式且没有分隔,所以我们需要先将中缀表达式的每一个操作数与操作符之间分隔开来,再将分隔后的中缀表达式转换为逆波兰表达式,随后再对逆波兰表达式进行运算求值。
实现
int Icp(char str) //栈外优先数
{
if (str == '#') { return 0; }
else if (str == '*' || str == '/' || str == '%') { return 4; }
else if (str == '(') { return 6; }
else if (str == '+' || str == '-') { return 2; }
else if (str == ')') { return 1; }
else { return -1; }
}
int Isp(char str) //栈内优先数
{
if (str == '#') { return 0; } //#优先数为0
else if (str == '*' ||str == '/' || str == '%') { return 5; } // * / %操作符优先数为 5
else if (str == '(') { return 1; } // ( 优先数为1
else if (str == '+' || str == '-') { return 3; } // + - 优先数为 3
else if (str == ')') { return 6; } // ) 优先数为 6
else { return -1; }
}
int CalRPN(stack<char>&ptr) //后缀求值
{
stack<char>str;
stack<int>Sum;
while (!ptr.empty()) //翻转
{
str.push(ptr.top());
ptr.pop();
}
while (!str.empty())
{
if (isdigit(str.top())) //字符
{
int num = str.top() - '0';
str.pop();
while (isdigit(str.top()))
{
num = num * 10 + str.top() - '0';
str.pop();
}
Sum.push(num);
}
else if (str.top()=='+'||str.top()=='-' || str.top() == '*' || str.top() == '/' || str.top() == '%')
{
int right = Sum.top();
Sum.pop();
int left = Sum.top();
Sum.pop();
if (str.top() == '+')
Sum.push(left + right);
else if (str.top() == '-')
Sum.push(left - right);
else if (str.top() == '*')
Sum.push(left * right);
else if (str.top() == '/')
{
if (right == 0)
{
perror("除数为0");
exit(EXIT_FAILURE);
}
else
Sum.push(left / right);
}
else if (str.top() == '%')
Sum.push(left % right);
else
{
cout << "非法表达式" << endl;
exit(EXIT_FAILURE);
}
str.pop();
}
else if (str.top()==' ')
{
str.pop();
}
}
return Sum.top();
}
int InalRpn(char *str) //中缀转后缀
{
int len = strlen(str);
stack<char>pstr; //后缀表达式栈
stack<char>sstr;
sstr.push('#'); //运算符栈
int count = 0;
cout << "后缀表达式为:";
while (*str)
{
if (*str == '+' || *str == '-' || *str == '*' || *str == '/' || *str == '%' || *str == '*' || *str == '(' || *str == ')')
{//如果是运算符入栈
if (pstr.top()!=' ')
{
cout << " ";
pstr.push(' ');
}
if (Icp(*str) > Isp(sstr.top())) //外大于内
{
sstr.push(*str);
str++;
}
else if (Icp(*str) < Isp(sstr.top())) //内大于外
{
cout << sstr.top();
pstr.push(sstr.top());
sstr.pop();
}
else if(Icp(*str) == Isp(sstr.top())) //优先级相同
{
if (sstr.top() == '(')
{
str++;
}
sstr.pop();
}
/*pstr.push(*str);
str++;*/
}
else if (isdigit(*str))
{
cout << *str;
pstr.push(*str);
str++;
}
else if(*str==' ')
{
str++;
}
}
while (sstr.top()!='#')
{
cout << sstr.top();
pstr.push(sstr.top());
sstr.pop();
}
cout << endl;
return CalRPN(pstr);
}
void PutSpace(char **str) //打空格
{// 12 3 4 + * 6 - 8 2 / +
int len = strlen(*str);
//stack<char>sstr;
char pstr[100];
int i = 0;
int j = 0;
for (i = 0; i < len; i++){
if (isdigit((*str)[i])){
//if (pstr[j - 1] == '/' || pstr[j - 1] == '*' || pstr[j - 1] == '%' || pstr[j - 1] == '+' || pstr[j - 1] == '-' || pstr[j - 1] == '(' || pstr[j - 1] == ')')
// pstr[j++] = ' ';
pstr[j++] = (*str)[i];
}
else{
pstr[j++] = ' ';
pstr[j++] = (*str)[i];
}
}
pstr[j] = '\0';
cout << "中缀表达式为>:"<<pstr << endl;
cout<<"运算值为"<<InalRpn(pstr)<<endl;
}
int main()
{
char *str = "12*(3+4)-6+8/2";
PutSpace(&str);
}