数据结构学习笔记——栈的应用

简单表达式求值

迷宫求解问题

简单表达式求值:
存储方式:顺序栈。
简单表达式:只包含加减乘除括号和数字的表达式。
中缀表达式:运算符位于两个操作数之间的表达式。
后缀表达式:运算符位于两个操作数之后的表达式。
前缀表达式:运算符位于两个操作数前面。

用字符数组exp来储存中缀表达式,用postexp字符数组来存储后缀表达式,运算符的临时存储以及优先级的处理通过运算符栈来处理。
在这里插入图片描述
例如对于中缀表达式“1 + 2+ 3”,扫描exp字符数组,首先把1存入postexp,然后扫描到了第一个+号,此时运算符栈里面没有运算符,那么直接存入运算栈,继续扫描,把2放入postexp,继续,之后遇到第二个运算符,也是加号,根据后缀表达式的定义,此时前面已经有两个数字了,所以postexp的第三个元素一定是一个运算符,这时候需要比较两个运算符的优先级了,很明显,对于同级的+运算,我们是从左到右运算的,所以此时应该把栈里面的+弹出,放到postexp中去,然后把第二个+存入运算符栈,其实还可以这样子理解:第二个+是在2和3中间的,又根据后缀表达式知,此时的运算符不能够是第二个+,第二个+应该是在3之后出现,所以postexp的第三个运算符一定是最先存入运算符栈的那个元素。

在扫描exp遇到一个运算符op时,如果栈为空,直接将其进栈,如果栈不空,
只有当op的优先级高于栈顶运算符的优先级时才直接将op进栈(op先出栈表示
先执行它);否则依次出栈运算符并存入postexp(出栈的运算符都比op先执行),
知道栈顶运算符的优先级小于op的优先级为止,然后将op进栈。

再来一个带有括号的例子:”2 * (1 + 3) -4",扫描exp数组,首先把2存入postexp,然后进栈*,遇到左括号“(”,其代表一个子表达式的开始,直接进栈,把1存入postexp,进栈+,把3存入postexp,下一步会扫描到右括号“)”,这代表一个子表达式的结束,把存储在左括号上面的运算符“+”出栈,放入postexp,出栈“(”,因为此时“(”已经没有用处,这时候扫描到了“-”,这时候在栈中的“*”的优先级高于“-”,所以“*”出栈,放入到postexp中,“-”入栈,4放入postexp中,扫描完毕,把剩下的运算符一一出栈,存入到postexp中。

在扫描exp遇到一个运算符op时,如果op为“(”,表示一个子表达式的开始,直接将其进栈;如果
op为“)”,表示一个子表达式的结束,则要出栈运算符并存入postexp直到栈顶元素为“(”,再将
“(”出栈;如果op是其他运算符,而栈顶为“(”,直接进栈。

把中缀表达式转化为后缀表达式的基本思想就是:
从左到右扫描中缀表达式exp,每扫一次当做一次循环,只有把每个数字或者是符号都彻底处理完了以后(比如把数字放到了postexp后缀表达式数组,把符号放到了运算符链栈里面)才进行下一个循环。对于每一次扫描,
若扫描到了数字,那么就把该数字放到postexp后缀表达式数组里面,当然这个数字可能不是单独的,他可能是一个数字的十位上的数,所以我们需要把后面连着的所有数字也同样放到postexp里面,直到扫描到的不是数字为止。由于数组是连续存储的我们不知道’1’'2‘表示的是12还是1和2,所以需要在数字放入完成之后加一个标志结束符’#‘
若扫描到了加号和减号,那么由于这中符号的优先级在四个符号中最低,所以前面的运算需要先进行,若没有左括号则全部pop出,并依次放到poestexp中直到栈空。比如说如果扫描到了加号或减号,这时候我们需要进运算符栈,但是在此之前,如果符号栈里面有加号,后缀表达式数组里面有两个数字‘1’和 ‘2’,这时按照运算法则,我们是不能先算后面的加法的,也就是不可能先算‘2’+‘x’的,所以符号栈里面的加号一定要先出去,然后再把扫描到符号的进栈,同样的对于左括号上的运算符也是如此,需要全部pop出,依次放到postexp中,直到栈顶元素是’(‘。理解这些话需要不断的在纸上写实例,让自己理解算法的过程,在纸上写实例写多了就会理解的。这是一种理解算法的很好的方法。
若扫描到了乘号和除号,若没有左括号,则pop运算符并放入postexp直到栈顶元素是加减符号或栈空,若有左括号,则pop运算符并放入postexp直到栈顶元素是加减符号或左括号。
若扫描到了左括号,那么直接进栈。
若扫描到了右括号,标志一个子表达式的结束,需要把在左括号前的全部运算符pop出,放到postexp中,然后把左括号也pop出,但是不放入postexp。

#include <stdio.h>
#include <malloc.h>
#define maxsize 100
typedef char Elemtype;
typedef struct LinkSt
{
	Elemtype signal;
	struct LinkSt *next;
 } LinkStNode;
 typedef struct
 {
 	Elemtype data[maxsize];
 	int top;
 } SqStack;

LinkStNode* InitLinkStack()
{
	LinkStNode *s;
	s = (LinkStNode *)malloc(sizeof(LinkStNode));
	s -> next = NULL;
	
	return s;
}//初始化一个链栈 

SqStack* InitSqStack()
{
	SqStack *s;
	s = (SqStack *)malloc(sizeof(SqStack));
	s -> top = -1;
	return s;
}//初始化一个顺序栈 
Elemtype GetElem(LinkStNode *SignalStack)
{
	Elemtype e;
	e = SignalStack -> next -> signal;
	
	return e;
 } 
 
Elemtype Pop(LinkStNode *SignalStack)
{
	Elemtype e;
	e = SignalStack -> next -> signal;//取出元素 
	LinkStNode *p;
	p = SignalStack -> next;
	SignalStack -> next = p -> next;
	free(p);
	p = NULL;//删除栈顶元素
	return e; 
}
_Bool judge(Elemtype e)
{
	if (e == '(') return 0;
	else return 1;
}
void PushLink(LinkStNode *SignalStack,Elemtype e)
{
	LinkStNode *s;
	s = (LinkStNode *)malloc(sizeof(LinkStNode));
	s -> signal = e;
	s -> next = NULL;
	if (SignalStack -> next != NULL) s -> next = SignalStack -> next;
	SignalStack -> next = s;
 } 

void PushSq(SqStack *postexp,Elemtype e)
{
	postexp -> top ++;
	postexp -> data[postexp -> top] = e;
}//把运算符进栈postexp 
SqStack* trans(char exp[maxsize])
{
	SqStack *postexp;
	postexp = InitSqStack();//创建一个顺序栈postexp
	LinkStNode *SignalStack;
	SignalStack = InitLinkStack();//创建一个链栈signalstack
	int i = 0;
	while(exp[i] != '\0')
	{
		switch (exp[i])
		{
			case '+':
			case '-':
				while(SignalStack -> next != NULL && GetElem(SignalStack) != '(')
				{
					Elemtype n;
					n = Pop(SignalStack);
					PushSq(postexp,n);
				 } 
				PushLink(SignalStack,exp[i]);
				i ++;
				break;
			case '*':
			case '/':
				while (SignalStack -> next != NULL &&GetElem(SignalStack) != '(' && GetElem(SignalStack) != '+' && GetElem(SignalStack) != '-')
				{
					Elemtype n;
					n = Pop(SignalStack);
					PushSq(postexp,n); 
				}
				PushLink(SignalStack,exp[i]);//把乘号除号放进去 
				i ++;
				break;
			case '(':
				PushLink(SignalStack,exp[i]);
				i ++;
				break;
			case ')':
				do
				{
					Elemtype n;
					n = Pop(SignalStack);
					PushSq(postexp,n); 
				}while(GetElem(SignalStack) != '(');
				Elemtype n;
				n = Pop(SignalStack);//去掉左括号 
			 
				i ++;
				break;
			default:
				do
				{
					PushSq(postexp,exp[i]);
					
					i ++;
				}while(exp[i] >= '0' && exp[i] <= '9');//输入数字字符 
				Elemtype k = '#';
				PushSq(postexp,k) ;
		}
	 } 
	while(SignalStack -> next != NULL)
	{
		Elemtype n;
		n = Pop(SignalStack);
		PushSq(postexp,n);
	}
	postexp -> top ++;
	postexp -> data[postexp -> top] = '\0';

	return postexp;
}
int main()
{
	int i = 0;
	char exp[maxsize];
	do
	{
		scanf("%c", &exp[i]);
	}while (exp[i ++] != '\n'); exp[i-1]='\0';//输入字符串成功。
	SqStack *postexp = trans(exp);//转化为后缀表达式 
	printf("%s", *postexp);
	
	
	 
	return 0;
 } 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值