栈的应用_就近匹配
检测括号是否匹配的能力
算法思路
从第一个字符开始扫描
当遇见普通字符时忽略,
当遇见左符号时压入栈中
当遇见右符号时从栈中弹出栈顶符号,并进行匹配
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
结束:
成功: 所有字符扫描完毕,且栈为空
失败:匹配失败或所有字符扫描完毕但栈非空
//LinkStack.h
#ifndef LINKSTACK_H
#define LINKSTACK_H
#include <stdlib.h>
#include <stdio.h>
//链式栈的结点
typedef struct LINKNODE{
struct LINKNODE* next;
}LinkNode;
//链式栈
typedef struct LINKSTACK{
LinkNode head;
int size;
}LinkStack;
//初始化函数
LinkStack* Init_LinkStack();
//入栈
void Push_LinkStack(LinkStack* stack, LinkNode* data);
//出栈
void Pop_LinkStack(LinkStack* stack);
//返回栈顶元素
LinkNode* Top_LinkStack(LinkStack* stack);
//返回栈元素的个数
int Size_LinkStack(LinkStack* stack);
//清空栈
void Clear_LinkStack(LinkStack* stack);
//销毁栈
void FreeSpace_LinkStack(LinkStack* stack);
#endif
//LinkStack.c
#include"LinkStack.h"
//初始化函数
LinkStack* Init_LinkStack(){
LinkStack* stack = (LinkStack*)malloc(sizeof(LinkStack));
stack->head.next = NULL;
stack->size = 0;
return stack;
}
//入栈
void Push_LinkStack(LinkStack* stack, LinkNode* data){
if (stack == NULL){
return;
}
if (data == NULL){
return;
}
data->next = stack->head.next;
stack->head.next = data;
stack->size++;
}
//出栈
void Pop_LinkStack(LinkStack* stack){
if (stack == NULL){
return;
}
if (stack->size == 0){
return;
}
//第一个有效结点
LinkNode* pNext = stack->head.next;
stack->head.next = pNext->next;
stack->size--;
}
//返回栈顶元素
LinkNode* Top_LinkStack(LinkStack* stack){
if (stack == NULL){
return NULL;
}
if (stack->size == 0){
return NULL;
}
return stack->head.next;
}
//返回栈元素的个数
int Size_LinkStack(LinkStack* stack){
if (stack == NULL){
return -1;
}
return stack->size;
}
//清空栈
void Clear_LinkStack(LinkStack* stack){
if (stack == NULL){
return;
}
stack->head.next = NULL;
stack->size = 0;
}
//销毁栈
void FreeSpace_LinkStack(LinkStack* stack){
if (stack == NULL){
return;
}
free(stack);
}
//栈的应用_就近匹配.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include"LinkStack.h"
typedef struct MYCHAR{
LinkNode node;
char* pAddres;
int index;
}MyChar;
int IsLeft(char c){
return c == '(';
}
int IsRight(char c){
return c == ')';
}
MyChar* CreateMyChar(char* p,int index){
MyChar* mychar = (MyChar*)malloc(sizeof(MyChar));
mychar->pAddres = p;
mychar->index = index;
return mychar;
}
void ShowError(char* str,int pos){
printf("%s\n",str);
for (int i = 0; i < pos;i ++){
printf(" ");
}
printf("A");
}
int main(void){
char* str = "1+2+6(dsf)df)sflp(sdfs)";
//创建栈容器
LinkStack* stack = Init_LinkStack();
char* p = str;
int index = 0;
while (*p != '\0'){
//如果左括号 直接进栈
if (IsLeft(*p)){
Push_LinkStack(stack, (LinkNode*)CreateMyChar(p,index));
}
//如果是右括号 从栈顶弹出元素 判断是不是左括号
if (IsRight(*p)){
if (Size_LinkStack(stack) > 0){
MyChar* mychar = (MyChar*)Top_LinkStack(stack);
if (IsLeft(*(mychar->pAddres))){
Pop_LinkStack(stack);
free(mychar);
}
}
else{
printf("右括号没有匹配的左括号:\n");
ShowError(str,index);
break;
}
}
p++;
index++;
}
while (Size_LinkStack(stack) > 0){
MyChar* mychar = (MyChar*)Top_LinkStack(stack);
printf("左括号没有匹配的右括号:\n");
ShowError(str, mychar->index);
Pop_LinkStack(stack);
free(mychar);
}
printf("\n");
system("pause");
return 0;
}
中缀表达式和后缀表达式
后缀表达式
将运算符放在数字后面 ===》 符合计算机运
中缀表达式
我们习惯的数学表达式 ===》符合人类思考习惯
中缀表达式转后缀表达式
8 + ( 3 – 1 ) * 5 ===> 8 3 1 – 5 * +
遍历中缀表达式中的数字和符号:
对于数字:直接输出
对于符号:
左括号:进栈
运算符号:与栈顶符号进行优先级比较
若栈顶符号优先级低:此符号进栈
(默认栈顶若是左括号,左括号优先级最低)
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出,直到匹配左括号
遍历结束:将栈中的所有符号弹出并输出
//mian.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkStack.h"
//判断是否是数字
int IsNumber(char c){
return c >= '0' && c <= '9';
}
//判断是不是左括号
int IsLeft(char c){
return c == '(';
}
//判断是不是右括号
int IsRight(char c){
return c == ')';
}
//判断是不是运算符号
int IsOperator(char c){
return c == '+' || c == '-' || c == '*' || c == '/';
}
//返回运算符号优先级
int GetPriority(char c){
if (c == '*' || c == '/'){
return 2;
}
if (c == '+' || c == '-'){
return 1;
}
return 0;
}
typedef struct MYCHAR{
LinkNode node;
char* p;
}MyChar;
//数字操作
void NumberOperate(char* p){
printf("%c", *p);
}
//创建MyChar
MyChar* CreateMyChar(char* p){
MyChar* mychar = (MyChar*)malloc(sizeof(MyChar));
mychar->p = p;
return mychar;
}
//左括号的操作
void LeftOperate(LinkStack* stack, char* p){
Push_LinkStack(stack, (LinkNode*)CreateMyChar(p));
}
//右括号操作
void RightOperate(LinkStack* stack){
//先判断栈中有没有元素
while (Size_LinkStack(stack) > 0){
MyChar* mychar = (MyChar*)Top_LinkStack(stack);
//如果匹配到左括号
if (IsLeft(*(mychar->p))){
Pop_LinkStack(stack);
free(mychar);
break;
}
//输出
printf("%c", *(mychar->p));
//弹出
Pop_LinkStack(stack);
//释放内存
free(mychar);
}
}
//运算符号的操作
void OperatorOperate(LinkStack* stack, char* p){
//先取出栈顶符号
MyChar* mychar = (MyChar*)Top_LinkStack(stack);
if (mychar == NULL){
Push_LinkStack(stack, (LinkNode*)CreateMyChar(p));
return;
}
//如果栈顶优先级低于当前字符的优先级 直接入栈
if (GetPriority(*(mychar->p)) < GetPriority(*p)){
Push_LinkStack(stack, (LinkNode*)CreateMyChar(p));
//return;
}
//如果栈顶符号优先级不低
else{
while (Size_LinkStack(stack) > 0){
MyChar* mychar2 = (MyChar*)Top_LinkStack(stack);
//如果优先级低 当前符号入栈
if (GetPriority(*(mychar2->p)) < GetPriority(*p)){
Push_LinkStack(stack, (LinkNode*)CreateMyChar(p));
return;
}
//输出
printf("%c", *(mychar2->p));
//弹出
Pop_LinkStack(stack);
//释放
free(mychar2);
}
}
}
int main01(void){
char* str = "8+(3-1)*5-6";
char* p = str;
//创建栈
LinkStack* stack = Init_LinkStack();
while (*p != '\0'){
//如果是数字
if (IsNumber(*p)){
NumberOperate(p);
}
//如果左括号 直接进栈
if (IsLeft(*p)){
LeftOperate(stack, p);
}
//如果是右括号
if (IsRight(*p)){
RightOperate(stack);
}
//如果是运算符号
if (IsOperator(*p)){
OperatorOperate(stack, p);
}
p++;
}
while (Size_LinkStack(stack) > 0){
MyChar* mychar = (MyChar*)Top_LinkStack(stack);
printf("%c", *(mychar->p));
Pop_LinkStack(stack);
free(mychar);
}
system("pause");
return 0;
}
根据后缀表达式求解
8 3 1 – 5 * +
遍历后缀表达式中的数字和符号
对于数字:进栈
对于符号:
从栈中弹出右操作数(即放到符号的右边)
从栈中弹出左操作数(即放到符号的左边)
根据符号进行运算
将运算结果压入栈中
遍历结束:栈中的唯一数字为计算结果
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkStack.h"
int IsNumber2(char c){
return c >= '0' && c <= '9';
}
typedef struct MYNUM{
LinkNode node;
int val;
}MyNum;
int Caculate(int left,int right,char c){
int ret = 0;
switch (c)
{
case '+':
ret = left + right;
break;
case '-':
ret = left - right;
break;
case '*':
ret = left * right;
break;
case '/':
ret = left / right;
break;
default:
break;
}
return ret;
}
int main(void){
//后缀表达式
char* str = "831-5*+";
char* p = str;
//创建栈
LinkStack* stack = Init_LinkStack();
while(*p != '\0'){
//如果是数字 直接入栈
if (IsNumber2(*p)){
MyNum* num = (MyNum*)malloc(sizeof(MyNum));
num->val = *p - '0'; //字符转数字
Push_LinkStack(stack, (LinkNode*)num);
}
else{
//先从栈中弹出右操作数
MyNum* right = (MyNum*)Top_LinkStack(stack);
int rightNum = right->val;
Pop_LinkStack(stack);
free(right);
//取出左操作数
MyNum* left = (MyNum*)Top_LinkStack(stack);
int leftNum = left->val;
Pop_LinkStack(stack);
free(left);
int ret = Caculate(leftNum, rightNum,*p);
//结果入栈
MyNum* num = (MyNum*)malloc(sizeof(MyNum));
num->val = ret;
Push_LinkStack(stack, (LinkNode*)num);
}
p++;
}
if (Size_LinkStack(stack) == 1){
MyNum* num = (MyNum*)Top_LinkStack(stack);
printf("运算结果是:%d\n",num->val);
Pop_LinkStack(stack);
free(num);
}
//释放栈
FreeSpace_LinkStack(stack);
system("pause");
return 0;
}