C语言通过栈实现逆波兰表达式

本人使用VC2019进行编程,该软件C中可以使用C++语法,故可能不严谨


前言

在校大学生,学习差,写写帖子长长写代码的记性。不好的地方大家请指正,谢谢。


以下是本篇文章正文内容,下面案例可供参考

一、栈

逻辑结构:线性,数据与数据间依然是一对一关系
存储结构:可以通过线性表或者链表实现
特点:大家可以把一般队列看做一根水管,这边进那边出,先进先出。栈就是个水瓶,进出都只有一个口,而且后进先出。所以在设计这样的数据结构的时候对出入口就会进行频繁的操作。所以对出入口位置都会设置指针或者下标方便操作。

二、波兰表达式

波兰表达式存在的意义就是使运算式中即使没有括号,也可以执行正确的运算顺序。例如a+b的波兰表达式可以写作+ab,逆波兰表达式则是ab+。概念大家自行百度。我主要讲讲怎么实现到逻辑:
1.首先我们拿到一个存放运算式的字符串。创建一个符号栈,用来放-+x/().
2.对字符串逐一扫描。如果是数字我们直接输出。
3.如果是运算符,而且此时符号栈空着的话就直接放进去。如果不是我们就比较栈顶符号与扫描符号的优先级,±最低,x/中间,()最高。
3.1.扫描符号高于栈顶符号,那就直接入栈,注意是高,等于不行。
3.2扫描符号不高于栈顶符号,输出栈顶符号,然后重复比较栈顶元素。也就是重复第3点。
————————————下面重要点!!!!————————————
4.如果扫到(,在定义时我们给了(最高优先级,所以(可以直接入栈,不用特殊操作,但是接下来扫描到的符号优先级肯定比(低,大家想想是不是。但是不能把(由3.2步骤弹出去!(弹出去的唯一条件就是扫描到了)。所以这里就需要在3.2的出栈条件再增加一条:栈顶不是(即可。
5.一直到扫描完这个字符串,然后将符号栈中剩下元素一直出栈输出就行。

三、代码实现

1.链栈定义与初始化

typedef struct stack {
	char data;
	struct stack* next;
}stack,*liststack;

void initstack(liststack &s) {
	s =(liststack) malloc(sizeof(stack));
	s->next = NULL;
}

2.完整代码

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

int operatorvalue[6] = {40,41,42,43,45,47};   //这是*-+/()的ascll码,用来判别运算式中扫描的字符是否是符号的

typedef struct stack {
	char data;
	struct stack* next;
}stack,*liststack;

void initstack(liststack &s) {
	s =(liststack) malloc(sizeof(stack));
	s->next = NULL;
	printf("init finished.\n");
}

void push(liststack& s, char c) {			//入栈
	stack *node;
	node = (liststack)malloc(sizeof(stack));
	node->data = c;
	node->next = s->next;
	s->next = node;
}

char pop(liststack& s) {					//出栈
	
		stack* top;
		top = s->next;
		char t = top->data;
		s->next = top->next;
		return t;
	
}

int priority(char c) {			          //return的数字就是运算优先级,这样才能比较
	if (c=='+'||c=='-')
	{
		return 1;
	}
	else if(c == '*' || c == '/')
	{
		return 2;
	}
	else
	{
		return 3;
	}
}

char gettop(liststack s) {					//获得栈顶元素
	if (s->next != NULL) return s->next->data;
}

int numORoperator(char c) {					//判断字符是数字还是运算符
	for (int i = 0; i < 6; i++)
	{
		if (operatorvalue[i] == int(c))		//operatorvalue[i]是开篇就定义的运算符ascll码数组
			return 1;		//运算符
	}
	return 0;				//数字
}

void nibolan(liststack &lsop,char arr[]) {		//通过此函数求得逆波兰表达式
	for (int i = 0; i < strlen(arr); i++)		//遍历字符串中所有字符
	{
		if(numORoperator(arr[i]))				//如果是运算符执行if里面语句
		{
			if (lsop->next==NULL)				//如果符号栈空,直接入栈
			{
				push(lsop, arr[i]);
			}
			else if (arr[i]==')')				//如果符号栈不空并且扫描到了‘)’,我们的逆波兰表达式不需要),所以不要入栈,(入栈都只是因为要它当作一个界限。
			{
				while (gettop(lsop)!='(')		//如果栈顶不是(,那么就一直出栈
				{
					char c = pop(lsop);
					printf("%c", c);
				}pop(lsop);						//注意这里再出栈的目的是让(出栈,我们的逆波兰表达式不需要()。上面循环结束条件就是栈顶为(。
			}
			else								//如果符号栈不空并且扫描到的不是),就执行这里面的语句
			{
				int toppriority = priority(gettop(lsop));       //获得栈顶元素优先级
				int arripriority = priority(arr[i]);            //获得当前扫描元素的优先级
				if (arripriority>toppriority||gettop(lsop)=='(')		//如果扫描元素优先级高于栈顶优先级,或者栈顶元素是(,则扫描元素入栈
				{
					push(lsop, arr[i]);
				}
				else   //如果扫描元素优先级不高于栈顶优先级,那就要栈顶出栈了
				{
					while (arripriority <= toppriority&&gettop(lsop)!='(')            //这里是重复判断栈顶与扫描符的优先级
					{
						if (lsop->next == NULL) break;
						char c = pop(lsop);
						printf("%c", c);
						toppriority = priority(gettop(lsop));
					}push(lsop, arr[i]);           //高于或等于扫描符的符号都出栈完了。让扫描符入栈
				}
			}
		}
		else                     //如果是数字,直接输出,这是与最上面的if一起的
		{
			printf("%c", arr[i]);
		}
	}
	while (lsop->next)			//将符号栈中剩余元素出栈
	{
		printf("%c",pop(lsop));
	}
}


int main() {
	liststack lsop;
	initstack(lsop);
	int temp = 0;
	char arr[255];
	printf("请输入中缀表达式:");
	scanf("%s", &arr);
	printf("逆波兰表达式为:\n");
	nibolan(lsop, arr);
	return 0;
}

总结

在波兰表达式那里个人觉得写的很臃肿,但是还没想好怎么改。感觉逻辑上一但确定,想改就比较想不到怎么改了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值