西北工业大学NOJ数据结构—008逆波兰式

本题为将一个中缀表达式转化为逆波兰式,同样为栈的应用,以下为原题(づ ̄3 ̄)づ╭❤~


有必要解释以下逆波兰式,其实就是后缀表达式,也就是计算机计算时识别的语言,比如上方的ab+c*,那么计算机就依次读取,a、b然后+,之后就可以计算a+b,然后c、*,也就是把a+b的和与c相乘,稍微详细一点的逆波兰式推荐知乎搜索:逆波兰式到底是什么鬼(虽然提问者有点睿智,但是几个回答者都是dalao得意),那么下面为题目分析

为了解决这个问题我创建了三个栈S1,S2,S3,其实从中缀到后缀的转化只需要一个栈(而从中缀到前缀则需要两栈),因为只需要将运算符放到栈S1中来回倒就ok(滑稽),额外创建的两个栈.......没什么用,储存表达式罢了,完全可以直接用字符串解决.......睿智了我......

思路分析,依次读取字符串的字符,先将一个“#”压进S1,作为一个比较的基础(\(^o^)/)

1.如果是字符,则直接压倒栈S2中,(知道为啥有S3了吗,因为压到S2中后输出是反的!反的!迫不得已最后再倒进S3在输出,哭唧唧)

2.如果是运算符,则就需要比较这个运算符和栈顶元素的优先级别了,假设之前栈顶的运算符为c1,后来读取的运算符为c2。

则有:如果c2优先级高于c1,那么c2压进S1栈储存

          如果c2优先级低于c1,那么S1将c1弹出并压进S2,然后比较新的S1的栈顶元素和c2,如果还是c2优先级别低,那就再弹一个c1,最后直到c1的优先级别低于c2,此时将c2压进栈S1。(大概就这样....其实意思就是要是c2想进栈,栈顶元素的优先级必须比他小,别忘了最下边还压着一个“#”,这玩意优先级别最低)

     那么他们的优先级顺序如下图所示,(很重要!!但是不需要背啊啥的,看看就懂了,乘除优先于加减,括号优先,就酱=_=)

        需要特别注意为‘(’,因为左括号的优先级其实是有改变的,如果c2是左括号,则优先级别最高,如果c1是左括号,则优先级别最低,稍微理解一下,因为如果下一个来的是左括号的话,那么你必须先运算括号里边的,所以优先级别超级高,但是如果左括号已经压进栈内了,那么你必须等到有一个右括号来跟他(交配),才能完成括号内的计算。

好了思路就这样,上代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct Node{//定义带有节点的链表
	char info;
	struct Node *next;
}Node;

typedef struct linkstack{//定义栈的栈顶指针
	struct Node *top;
}stack;

stack *creat(void)
{
	stack *plstack;//创建一个空栈并返回指针
	plstack=(struct linkstack*)malloc(sizeof(struct linkstack));
	if(plstack!=NULL)
		plstack->top=NULL;
	else
		printf("out!\n");
	return plstack;
}

int is_empty(stack *plstack)//检查栈是否为空
{
	return(plstack->top==NULL);
}

void push(stack *plstack,char x)//动态申请并将一元素入栈
{
	struct Node *p;
	p=(struct Node*)malloc(sizeof(struct Node));
	if(p==NULL)
		printf("out!\n");
	else
	{
		p->info=x;
		p->next=plstack->top;
		plstack->top=p;
	}
}

char pop(stack *plstack)
{//如果栈不为空则将栈顶元素出栈并返回该元素
	struct Node *p;
	char elem;
	if(is_empty(plstack))
		printf("out!5");
	else
	{
		p=plstack->top;
		elem=p->info;
		plstack->top=plstack->top->next;
		free(p);
	}
	return elem;
}

char toplink(stack *plstack)//如果栈非空则返回栈顶元素
{
	if(is_empty(plstack))
		printf("out!7");
	return plstack->top->info;
}

stack *nibolan(char *e)
{
	stack *s1,*s2,*s3;
	s1=creat();
	s2=creat();
	s3=creat();//创建三个栈
	push(s1,'#');//在一个中压进#
	char *p=e,ch,cp;
	int length=0;
	for(;*p!='\0';p++)
	{
		switch(*p)
		{
			case'(':{
				push(s1,*p);
				break;   //左括号直接入栈
			}
			case')':{    //如果是右括号则将左括号之前的全部出栈并依此压进2栈
				while(toplink(s1)!='(')
				{
					ch=pop(s1);
					push(s2,ch);
				}
				cp=pop(s1);    //将左括号出栈,不要了,因为后缀表达式不需要括号
				break;
			}
			case'+':
			case'-':{
				for(ch=toplink(s1);ch!='#';ch=toplink(s1))//一出现加减号那么可以说一下就可以运算之前所有的
				{             //如果是加号减号则检查栈顶元素
					if(ch=='(')
					{
						break;  //如果是左括号那显然直接压进去就ok
					}
					else{      //但是如果是加减乘除号,就要考虑往外弹了,以为之前压进去的加减号的优先级也是大于后来的加减号
						ch=pop(s1);     //优先级低依此出栈并压进2栈
						push(s2,ch);
					}
				}
				push(s1,*p);           //到最后再吧这个加减号压进S1
				length++;
				break;
			}
			case'*':
			case'/':{
				for(ch=toplink(s1);ch!='#'&&ch!='+'&&ch!='-';ch=toplink(s1))
				{           //如果是乘号和除号则判定是否优先  比他低的优先级就是加减号
					if(ch=='(')
					{
						break;
					}
					else{//同样 之前的若是乘除号,也是先进的优先级高于后来的
						ch=pop(s1);
						push(s2,ch);
					}
				}
				push(s1,*p);     //直到碰到优先级高直接压进
				length++;
				break;
			}
			default:
			push(s2,*p);       //其他数字直接压进2栈
			length++;
		}
	}
	while(!is_empty(s1)&&toplink(s1)!='#')
	{          //结束后1栈不空则依此从出栈并压进2栈
		ch=pop(s1);
		push(s2,ch);
	}
	while(!is_empty(s2))
	{       //依此将2栈出栈压进三战逆置
		ch=pop(s2);
		push(s3,ch);
	}
	return (s3);
}

void show(stack *p)
{          //从栈顶元素开始出栈,并输出出栈元素
	stack *a=p;
	while(!is_empty(a))
	{
		printf("%c",a->top->info);
		pop(a);
	}
}

int main()
{
	char a[100],*e;
	stack *c;
	e=&a[0];
	scanf("%s",a);
	c=nibolan(e); //调用逆波兰函数得到栈3
	show(c);   //输出逆波兰式
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值