栈的基本概念
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
代码的创建
定义
typedef struct CharStack{
int top;
int data[MAX];// 最大长度是固定的
} *CharStackPtr;
初始化
// 初始化一个空字符堆栈
CharStackPtr charStackInit(){
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(CharStack));
resultPtr->top = -1;//当栈顶是-1的时候表示栈里没有元素
return resultPtr;
}
打印栈
// 输出栈
void outputStack(CharStackPtr paraStack){
for(int i = 0;i <= paraStack->top;i++)
{
printf("%c ", paraStack->data[i]);
}
printf("\r\n");
}
压栈
void push(CharStackPtr paraStackPtr, int paraValue){
//第一步:空间检查,看栈的空间是否足够
if(paraStackPtr->top >= MAX-1){
printf("不能将元素存放进栈,栈的空间已经满了\r\n");
return;
}
//第二步:更新栈的栈顶
paraStackPtr->top++;
//第三步:将元素放入栈中
paraStackPtr->data[paraStackPtr->top] = paraValue;
}
弹栈(栈顶)
// 将一个元素从栈中拿出来(弹栈)
char pop(CharStackPtr paraStackPtr){
//第一步:空间检查,看栈的空间是否足够
if(paraStackPtr->top < 0)// 小于0表示此时栈当中不存在元素
{
printf("不能从栈当中拿出一个元素,栈的空间为0\r\n");
return '\0';
}
//第二步:更新栈的栈顶
paraStackPtr->top--;
//第三步:将元素拿出来
return paraStackPtr->data[paraStackPtr->top + 1];
}
计算栈的长度
// 计算栈的长度
int CountLength(CharStackPtr paraStackPtr)
{
if(paraStackPtr->top < 0)return 0;
else
{
return paraStackPtr->top+1;
}
}
功能测试
// 检测压栈弹栈的功能是否完好
void Test(){
printf("---- 检测开始 ----\r\n");
// 初始化
CharStackPtr tempStack = charStackInit();
printf("经过初始化后,这个栈是:");
outputStack(tempStack);
// 压栈
for(char ch = 'a';ch < 'm';ch++)
{
printf("Pushing %c.\r\n",ch);
push(tempStack,ch);
outputStack(tempStack);
int cnt = CountLength(tempStack);
printf("此时栈的长度为%d\r\n",cnt);
}
// 弹栈
for(int i = 0;i < 3;i ++)
{
int ch = pop(tempStack);
printf("Poping %c.\r\n",ch);
outputStack(tempStack);
int cnt = CountLength(tempStack);
printf("此时栈的长度为%d\r\n",cnt);
}
printf("---- 检测完毕 ----\r\n");
}
完整代码以及运行结果
#include<stdio.h>
#include<malloc.h>
#define MAX 10
typedef struct CharStack{
int top;
int data[MAX];// 最大长度是固定的
} *CharStackPtr;
// 输出栈
void outputStack(CharStackPtr paraStack){
for(int i = 0;i <= paraStack->top;i++)
{
printf("%c ", paraStack->data[i]);
}
printf("\r\n");
}
// 初始化一个空字符堆栈
CharStackPtr charStackInit(){
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(CharStack));
resultPtr->top = -1;//当栈顶是-1的时候表示栈里没有元素
return resultPtr;
}
// 将一个元素放入栈中(压栈)
void push(CharStackPtr paraStackPtr, int paraValue){
//第一步:空间检查,看栈的空间是否足够
if(paraStackPtr->top >= MAX-1){
printf("不能将元素存放进栈,栈的空间已经满了\r\n");
return;
}
//第二步:更新栈的栈顶
paraStackPtr->top++;
//第三步:将元素放入栈中
paraStackPtr->data[paraStackPtr->top] = paraValue;
}
// 将一个元素从栈中拿出来(弹栈)
char pop(CharStackPtr paraStackPtr){
//第一步:空间检查,看栈的空间是否足够
if(paraStackPtr->top < 0)// 小于0表示此时栈当中不存在元素
{
printf("不能从栈当中拿出一个元素,栈的空间为0\r\n");
return '\0';
}
//第二步:更新栈的栈顶
paraStackPtr->top--;
//第三步:将元素拿出来
return paraStackPtr->data[paraStackPtr->top + 1];
}
// 计算栈的长度
int CountLength(CharStackPtr paraStackPtr)
{
if(paraStackPtr->top < 0)return 0;
else
{
return paraStackPtr->top+1;
}
}
// 检测压栈弹栈的功能是否完好
void Test(){
printf("---- 检测开始 ----\r\n");
// 初始化
CharStackPtr tempStack = charStackInit();
printf("经过初始化后,这个栈是:");
outputStack(tempStack);
// 压栈
for(char ch = 'a';ch < 'm';ch++)
{
printf("Pushing %c.\r\n",ch);
push(tempStack,ch);
outputStack(tempStack);
int cnt = CountLength(tempStack);
printf("此时栈的长度为%d\r\n",cnt);
}
// 弹栈
for(int i = 0;i < 3;i ++)
{
int ch = pop(tempStack);
printf("Poping %c.\r\n",ch);
outputStack(tempStack);
int cnt = CountLength(tempStack);
printf("此时栈的长度为%d\r\n",cnt);
}
printf("---- 检测完毕 ----\r\n");
}
int main(){
Test();
}
括号的匹配应用
bool bracketMatching(char* paraString, int paraLength) {
// 初始化,将#放入栈底
CharStackPtr tempStack = charStackInit();
push(tempStack, '#');
char tempChar, tempPopedChar;
// 字符串的处理
for (int i = 0; i < paraLength; i++) {
tempChar = paraString[i];
switch (tempChar) {// 判断符号的种类
case '(':
case '[':
case '{':
push(tempStack, tempChar);// 如果是前括号者将其压入栈中
break;
case ')':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '(') {
return false;
}
break;
case ']':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '[') {
return false;
}
break;
case '}':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '{') {
return false;
}
break;// 这里是如果检测到后括号,则马上将当前栈中的栈顶给调出来,
// 即检查它和它的上一个括号是否属于同一类,如果属于同一类,则说明括号是匹配的;反之则不匹配
default:
// 表名此时检测到的不是括号,是数字,因此不做任何操作
break;
}
}
tempPopedChar = pop(tempStack);
if (tempPopedChar != '#') {
return true;
}
return true;
}
功能测试
// 功能测试 (1表示正确,0表示错误)
void bracketMatchingTest() {
char* tempExpression = "[24*(16-8)-12]";
bool tempMatch = bracketMatching(tempExpression, 14);
printf("%s'是否括号匹配? %d \r\n", tempExpression, tempMatch);
tempExpression = "(5*12+3)*32-1)";
tempMatch = bracketMatching(tempExpression, 14);
printf("%s是否括号匹配? %d \r\n", tempExpression, tempMatch);
tempExpression = "(2-1)(3-1)(4*(5-1))";
tempMatch = bracketMatching(tempExpression, 19);
printf("%s是否括号匹配? %d \r\n", tempExpression, tempMatch);
tempExpression = "(2*{3-1}[4*6])";
tempMatch = bracketMatching(tempExpression, 13);
printf("%s是否括号匹配? %d \r\n", tempExpression, tempMatch);
tempExpression = "2*16)(3-12";
tempMatch = bracketMatching(tempExpression, 10);
printf("%s是否括号匹配? %d \r\n", tempExpression, tempMatch);
}
运行结果
栈的应用(表达式求值)
现附上大佬的代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <unordered_map>
using namespace std;
stack<int> num;
stack<char> op;
void eval()
{
auto b = num.top();
num.pop();
auto a = num.top();
num.pop();
auto c = op.top();
op.pop();
int x;
if (c == '+') x = a + b;
else if (c == '-') x = a - b;
else if (c == '*') x = a * b;
else x = a / b;
num.push(x);
}
int main()
{
unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
string str;
cin >> str;
for (int i = 0; i < str.size(); i ++ )
{
auto c = str[i];
if (isdigit(c))
{
int x = 0, j = i;
while (j < str.size() && isdigit(str[j]))
x = x * 10 + str[j ++ ] - '0';
i = j - 1;
num.push(x);
}
else if (c == '(') op.push(c);
else if (c == ')')
{
while (op.top() != '(') eval();
op.pop();
}
else
{
while (op.size() && op.top() != '(' && pr[op.top()] >= pr[c]) eval();
op.push(c);
}
}
while (op.size()) eval();
cout << num.top() << endl;
return 0;
}
说实话,刚开始看这个代码的时候我人都是傻的,因为很多都不是很理解,只能一个一个地去百度,但是至今有些地方我也不是很能理解,比如unordered_map的用法到底是什么,也欢迎大家来给我解惑
下面则是我自己基于该代码的理解而写出的表达式求值代码
核心代码
// 优先级的判断
ch2har prech2ede(ch2har ch2h1,ch2har ch2h2)//ch2h是栈顶字符,ch2 是表达式字符
{
switch2h(ch2h)
{
case '+':
if(ch2=='+')return '>';
if(ch2=='-')return '>';
if(ch2=='*')return '<';
if(ch2=='/')return '<';
if(ch2=='(')return '<';
if(ch2==')')return '>';
if(ch2=='=')return '>';
case '-':
if(ch2=='+')return '>';
if(ch2=='-')return '>';
if(ch2=='*')return '<';
if(ch2=='/')return '<';
if(ch2=='(')return '<';
if(ch2==')')return '>';
if(ch2=='=')return '>';
case '*':
if(ch2=='+')return '>';
if(ch2=='-')return '>';
if(ch2=='*')return '>';
if(ch2=='/')return '>';
if(ch2=='(')return '<';
if(ch2==')')return '>';
if(ch2=='=')return '>';
case '/':
if(ch2=='+')return '>';
if(ch2=='-')return '>';
if(ch2=='*')return '>';
if(ch2=='/')return '>';
if(ch2=='(')return '<';
if(ch2==')')return '>';
if(ch2=='=')return '>';
case '(':
if(ch2=='+')return '<';
if(ch2=='-')return '<';
if(ch2=='*')return '<';
if(ch2=='/')return '<';
if(ch2=='(')return '<';
if(ch2==')')return '=';
if(ch2=='=')return ' ';
case ')':
if(ch2=='+')return '>';
if(ch2=='-')return '>';
if(ch2=='*')return '>';
if(ch2=='/')return '>';
if(ch2=='(')return ' ';
if(ch2==')')return '>';
if(ch2=='=')return '>';
case '=':
if(ch2=='+')return '<';
if(ch2=='-')return '<';
if(ch2=='*')return '<';
if(ch2=='/')return '<';
if(ch2=='(')return '<';
if(ch2==')')return '0';
if(ch2=='=')return '=';
}
}
// 计算
int eval(int a,int b,char ch)
{
switch(ch){
case '+':return a+b;
case '-':return a-b;
case '*':return a*b;
case '/':
if(b==0)printf("错误");
else return a/b;
}
}
// 判断运算符
int judge(char ch)
{
if(ch=='+' || ch=='-' || ch=='*' || ch=='/' || ch=='(' || ch==')' || ch=='=')return 1;// 表示是运算符
else return 0; //表示不是运算符
}
// 表达式求值
int evaluateExpression(char *paraExpression)
{
StackPtr tempStack1=initStack();
StackPtr tempStack2=initStack();
int a,b,ch,x,x1,x2;
char ch1;
int i = 0;
push(tempStack2,'=');
ch1 = paraExpression[i++];
while(ch1 != '=' || getTop(tempStack2) != '=')
{
if(judge(ch1))
{
switch(priority(getTop(tempStack2),ch1))
{
case'<':
push(tempStack2,ch1);
ch1 = paraExpression[i++];
break;
case'>':
ch = pop(tempStack2);
b = pop(tempStack1);
a = pop(tempStack1);
push(tempStack1,evaluate(a,ch,b));
break;
case'=':
x = pop(tempStack2);
ch1 = paraExpression[i++];
break;
}
}
else if(isdigit(ch1))
{
x1 = ch1-'0';
push(tempStack1,x1);
x2 = x1;
ch1 = paraExpression[i++];
while(isdigit(ch1))
{
x1 = ch1 - '0';
x2 = 10*x2 + x1;
x = pop(tempStack1);
push(tempStack1,x2);
ch1 = paraExpression[i++];
}
}
else if(ch1 == ' ')
{
while(ch1 == ' ')
{
ch1 == paraExpression[i++];
}
}
else
{
printf("错误\n");
}
}
return getTop(tempStack1);
}