什么是栈
栈是一种运算受限的线性表,它限定只能在表的一端进行插入和删除操作。栈的结构特性是:后进先出LIFO ( Last In First Out)。栈又被称为后进先出表。
栈顶:允许插入和删除的一端称作栈顶
栈顶:不允许插入和删除的一端称作栈底
链式栈
栈基本操作
-
创建栈:create_stack
-
入栈: push_stack
-
出栈: pop_stack
-
获取栈顶元素:top_stack
-
栈是否为空:empty_stack
-
栈元素个数: size_stack
数组链表实现代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int DataType;
typedef struct Stack
{
DataType* memory;//数据
int top;//顶点位置
int maxSize;//最大存入量
}Stack;
Stack* create_stack()
{
Stack* stack = (Stack*)calloc(1, sizeof(Stack));
assert(stack);
stack->top = -1;
return stack;
}
void push_stack(Stack* stack, DataType data)
{
assert(stack);
//内存自动增长
if (stack->top+1 == stack->maxSize)
{
stack->maxSize += 10;
DataType* temp = (DataType*)realloc(stack->memory, sizeof(DataType) * stack->maxSize);//重新分配内存并赋值为一
assert(temp);
stack->memory = temp;
}
stack->memory[++stack->top] = data;
}
int size_stack(Stack* stack)
{
return stack->top + 1;
}
bool empty_stack(Stack* stack)
{
assert(stack);
return stack->top == -1;
}
#if 0
//个人喜欢写法
void pop_stack(Stack* stack)
{
assert(stack);
if (empty_stack(stack))
{
printf("栈为空无法出栈!\n");
return;
}
stack->top--;
}
DataType top_stack(Stack* stack)
{
assert(stack);
return stack->memory[stack->top];
}
#endif
DataType pop_stack_(Stack* stack)
{
return stack->memory[stack->top--];
}
void pop_stack_s(Stack* stack,DataType* value)
{
*value=stack->memory[stack->top--];
}
int main()
{
Stack* stack = create_stack();
push_stack(stack,1);
push_stack(stack,2);
push_stack(stack,3);
while (!empty_stack(stack))
{
#if 0
printf("%d\t", top_stack(stack));
pop_stack(stack);
#endif
//printf("%d\t",pop_stack_(stack));
int value = 0;
pop_stack_s(stack, &value);
printf("%d\t", value);
}
printf("\n");
return 0;
}
链式表实现代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node* next;//地址指向下一个链表元素(下一个要从栈出来的元素)
}Node;
Node* create_node(DataType data)
{
Node* newNode = (Node*)calloc(1, sizeof(Node));
assert(newNode);
newNode->data = data;
return newNode;
}
typedef struct Stack
{
Node* top;
int count;
}Stack;
Stack* create_stack()
{
Stack* stack = (Stack*)calloc(1, sizeof(Stack));
assert(stack);
return stack;
}
bool empty_stack(Stack* stack)//将元素个数设为空(清空)
{
assert(stack);
return stack->count == 0;
}
int size_stack(Stack* stack) //返回元素个数
{
assert(stack);
return stack->count;
}
DataType top_stack(Stack* stack)
{
assert(stack);
assert(stack->top);
return stack->top->data;
}
void push_stack(Stack* stack, DataType data)
{
assert(stack);
Node* newNode = create_node(data);
newNode->next = stack->top;
stack->top = newNode;
stack->count++;元素加一
}
void pop_stack(Stack* stack)
{
assert(stack);
if (stack->top == NULL)
{
printf("栈为空,无法出栈\n");
return; //exit(1);
}
Node* nextNode = stack->top->next;
free(stack->top);
stack->top = nextNode;
stack->count--;
}
int main()
{
Stack* stack = create_stack();
push_stack(stack, 1);
push_stack(stack, 2);
push_stack(stack, 3);
while (!empty_stack(stack))
{
printf("%d\t", top_stack(stack));
pop_stack(stack);
}
printf("\n");
return 0;
}
栈的应用小实例
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//({})
bool match(const char* str)
{
//创建栈
char stack[1024];
int top = -1;
int i = 0;
while (str[i] != '\0')
{
if (str[i] == '(')
{
//入栈操作
stack[++top] = str[i];
}
else if (str[i] == ')')
{
//出栈
if (top > -1)
{
top--;
}
else
{
return false;
}
}
i++;
}
if (top == -1)
{
return true;
}
else
{
return false;
}
}
int main()
{
while (true)
{
char str[1024] = "";
gets_s(str, 1024);
if (match(str) == true)
{
printf("匹配!\n");
}
else
{
printf("不匹配\n");
}
}
return 0;
}
运行结果
实例2:表达式求值详解
中缀表达式
我们把平时所用的标准四则运算表达式,即“9+(3-1)×3+10÷2”叫做中缀表达式。因为所有的运算符号都在两数字的中间。
后缀表达式
将中缀表达式转化为后缀表达式:栈内只存符号,遇到右边括号就要出栈,出到左括号,遇到乘 法要比优先级
后缀表达式也叫作逆波兰表达式,对于“9+(3-1)×3+10÷2”,如果要用后缀表示法应该是什么样子:“9 3 1-3*+10 2/+”,这样的表达式称为后缀表达式,叫后缀的原因在于所有的符号都是在要运算数字的后面出现。后缀表达式如何求解表达式的值?
-
遍历后缀表达式,如果遇到数字则直接入栈,如果遇到操作符,则弹出栈顶的两个元素,进行计算后将结果入栈。
-
最终,栈内剩余的元素就是整个表达式的计算结果。
照着原理可以写出如下代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <ctype.h>
typedef double DataType;
#if 0
enum ValueType {IsChar,isNumber,IsDouble};
typedef struct Data
{
int type;
union
{
char strValue;
int intVlaue;
double doubleValue;
};
}Data;
typedef struct Stack_
{
Data* memory;
int top;
int maxSize;
}Stack_;
#endif
typedef struct Stack
{
DataType* memory;
int top;
int maxSize;
}Stack;
Stack* create_stack()
{
Stack* stack = (Stack*)calloc(1, sizeof(Stack));
assert(stack);
stack->top = -1;
return stack;
}
void push_stack(Stack* stack, DataType data)
{
assert(stack);
//内存自动增长
if (stack->top + 1 == stack->maxSize)
{
stack->maxSize += 10;
DataType* temp = (DataType*)realloc(stack->memory, sizeof(DataType) * stack->maxSize);
assert(temp);
stack->memory = temp;
}
stack->memory[++stack->top] = data;
}
int size_stack(Stack* stack)
{
return stack->top + 1;
}
bool empty_stack(Stack* stack)
{
assert(stack);
return stack->top == -1;
}
void pop_stack(Stack* stack)
{
assert(stack);
if (empty_stack(stack))
{
printf("栈为空无法出栈!\n");
return;
}
stack->top--;
}
DataType top_stack(Stack* stack)
{
assert(stack);
return stack->memory[stack->top];
}
//辅助函数
//判定是否是运算符
bool is_operator(char key)
{
return key == '+' || key == '-' || key == '*' || key == '/';
}
//优先级判定
int pri_operator(char key)
{
switch (key)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
//中缀转后缀
void midFix_top_lastFix(char* midFix, char* lastFix)
{
Stack* stack = create_stack();
char* p = midFix;
char* q = lastFix;
while (*p != '\0')
{
//3.3+43
if (isdigit(*p)) //#include <ctype.h>
{ //如果是数字
while (isdigit(*p) || *p == '.')
{
*q = *p;
q++;
p++;
}
//数字与数字要有间隔
*q = ' ';
q++;
}
else if (*p == '+' || *p == '-' || *p == '*' || *p == '/')
{
//如果运算符
int pri = pri_operator(*p); //当前字符的优先级
//低于优先一直出栈,把栈中的的运算符拿出来放到后缀表达式中
while (!empty_stack(stack)&&is_operator(top_stack(stack))&&pri_operator(top_stack(stack))>=pri)
{
char op = top_stack(stack);
pop_stack(stack);
//出栈的运算符要放到后缀表达式中
*q = op;
q++;
*q = ' ';
q++;
}
//高于 入字符栈
push_stack(stack, *p);
p++;
}
else if (*p == '(')
{
push_stack(stack, *p);
p++;
}
else if (*p == ')')
{
//遇到右边括号出栈到左边括号为止
while (!empty_stack(stack) && top_stack(stack) != '(')
{
char op = top_stack(stack);
pop_stack(stack);
*q = op;
q++;
*q = ' ';
q++;
}
if (!empty_stack(stack) && top_stack(stack) == '(')
{
pop_stack(stack);//将括号删掉
}
else
{
printf("error\n");
}
p++;
}
else
{
//其他的直接跳过
p++;
}
}
//栈中剩余的运算符 直接连接到后缀表达式中
while (!empty_stack(stack))
{
char op = top_stack(stack);
pop_stack(stack);
*q = op;
q++;
*q = ' ';
q++;
}
//字符串结束标记
*(q - 1) = '\0';
}
//辅助函数
double operator_num(double left, double right, char op)
{
switch (op)
{
case '+':
return left + right;
break;
case '-':
return left - right;
break;
case '*':
return left * right;
break;
case '/':
return left / right;
break;
default:
return 0.0;
break;
}
}
double calc_result(char* lastFix)
{
Stack* stack = create_stack();
char* p = lastFix;
while (*p != '\0')
{
if (isdigit(*p))
{
//23.456
double num = *p - '0'; //2
p++;
while (isdigit(*p) || *p == '.') //234
{
if (*p == '.')
{
p++;
double dec = 0.1;
while (isdigit(*p))
{
num += (*p - '0') * dec;
p++;
dec /= 10;
}
break;
}
else
{
num = num * 10 + (*p - '0'); //2*10+3-'0'=23 23*10+4-'0'=234
p++;
}
}
//记得入栈
push_stack(stack, num);
}
else if (*p == '+' || *p == '-' || *p == '*' || *p == '/')
{
double right = top_stack(stack);
pop_stack(stack);
double left = top_stack(stack);
pop_stack(stack);
double result = operator_num(left, right, *p);
push_stack(stack, result);
p++;
}
else
{
p++;
}
}
double value = top_stack(stack);
pop_stack(stack);
return value;
}
int main()
{
char midFix[100] = "";
char lastFix[100] = "";
while (true)
{
printf("input midFix:");
gets_s(midFix, 100);
midFix_top_lastFix(midFix, lastFix);
printf("lastFix:%s\n", lastFix);//测试后缀表达式
printf("%s=%lf\n", midFix, calc_result(lastFix));//计算数值
}
return 0;
}