中缀表达式转换为前缀表达式

一、问题描述

将中缀表达式转换为前缀表达式

如:将2*3/(2-1)+5*(4-1)转化为+/*23-21*5-41


二、算法流程

1)求输入串的逆序。

2)检查输入的下一元素。

3)假如是操作数,把它添加到输出串中。

4)假如是闭括号,将它压栈。

5)假如是运算符,则

i)假如栈空,此运算符入栈。

ii)假如栈顶是闭括号,此运算符入栈。

iii)假如它的优先级高于或等于栈顶运算符,此运算符入栈。

iv)否则,栈顶运算符出栈并添加到输出串中,重复步骤5

6)假如是开括号,栈中运算符逐个出栈并输出,直到遇到闭括号。闭括号出栈并丢弃。

7)假如输入还未完毕,跳转到步骤2

8)假如输入完毕,栈中剩余的所有操作符出栈并加到输出串中。

9)求输出串的逆序。 */

(此算法流程是从http://blog.csdn.net/tianya0609/article/details/6473660 copy过来的)


三、实现代码(C语言)

 



 

#include <stdio.h>
#include <stdlib.h>
#include "stack_yutao.h"

void reverse_and_copy(const char *source, char *dest);
void reverse_self(char *array);
void display_array(const char *array);
void reverse_infix_to_reverse_prefix(char reverse_infix[], char reverse_prefix[]);
int get_priority(char ch);

int main()
{
	char infix_array[15] = "1+2*9/(8-6)";
	char prefix_array[15];
	char reverse_infix[15];
	
	printf("display infix_array:	");
	display_array(infix_array);
	reverse_and_copy(infix_array,reverse_infix);//将infix反转得到reverse_infix
	printf("display reverse_infix:	");
	display_array(reverse_infix);

	reverse_infix_to_reverse_prefix(reverse_infix,prefix_array);//将反转的infix转换为反转的prefix
	printf("display prefix_array:	");
	display_array(prefix_array);

	reverse_self(prefix_array);//将得到的反转的prefix自反,得到最后的prefix
	printf("display prefix_array:	");
	display_array(prefix_array);

	system("pause");
	return 0;
}

void reverse_infix_to_reverse_prefix(char reverse_infix[], char reverse_prefix[])
{
	int i = 0;
	stack my_stack;
	stack *s = &my_stack;
	int stack_size = 10;
	int len = 0;
	int index = 0;
	char temp;
	int flag;

	initStack(s,stack_size);
	i = 0;
	while('\0' != reverse_infix[i ++]);
	len = i - 1;
	for(i = 0; i < len; i ++)
	{
		if('0' <= reverse_infix[i] && reverse_infix[i] <= '9')
		{
			reverse_prefix[index ++] = reverse_infix[i];
			continue;
		}
		switch(reverse_infix[i])
		{
		case '(':		//对于'(',弹出栈中元素并保存到输出序列中,直到遇到')',')'直接抛弃
			get_top(s,&temp);
			while(')' != temp)
			{
				reverse_prefix[index ++] = temp;
				pop(s);
				get_top(s,&temp);
			}
			if(')' != temp)
			{
				pop(s);
			}
			break;
		case ')':		//对于')',直接入栈
			push(s,reverse_infix[i]);
			break;
		case '+':
		case '-':
		case '*':
		case '/':
		case '%':
			get_top(s,&temp);
			flag = (is_stack_empty(s)) || (')' == temp) || (get_priority(reverse_infix[i]) >= get_priority(temp));
			while(!flag)	//当栈为空、栈顶为')'或当前符号的优先级大于等于栈顶符号的优先级时,直接入栈;
			{				//否则就一直从栈中弹出元素保存到输出直到该条件满足
				reverse_prefix[index ++] = temp;
				pop(s);
				get_top(s,&temp);
				flag = (is_stack_empty(s)) || (')' == temp) || (get_priority(reverse_infix[i]) >= get_priority(temp));
			}
			push(s,reverse_infix[i]);
			break;
		default:
			printf("There must be something wrong in the program ! ---reverse_infix_to_reverse_prefix()\n");
			break;
		}
	}
	reverse_prefix[index] = '\0';
}

int get_priority(char ch)
{
	int priority = -1;
	switch(ch)
	{
	case '+':
	case '-':
		priority = 0;
		break;
	case '*':
	case '/':
	case '%':
		priority = 1;
		break;
	default:
		printf("There must be something wrong in the program ! ---int get_priority(char ch)\n");
		system("pause");
		break;
	}
	return priority;
}

void reverse_and_copy(const char *source, char *dest)
{
	int i = 0;
	int len = 0;
	while('\0' != source[i ++]);
	len = i - 1;
	if(0 == len)
	{
		return ;
	}
	for(i = 0; i < len; i ++)
	{
		dest[i] = source[len - 1 -i];
	}
	dest[len] = '\0';
}

void reverse_self(char *array)
{
	int i = 0;
	int len = 0;
	int temp;
	
	while('\0' != array[i ++]);
	len = i - 1;
	if(0 == len)
	{
		return ;
	}
	for(i = 0; i < len / 2; i ++)
	{
		temp = array[i];
		array[i] = array[len - 1 - i];
		array[len - 1 - i] = temp;
	}
	array[len] = '\0';
}

void display_array(const char *array)
{
	int i = 0;
	while('\0' != array[i])
	{
		printf("%c ",array[i ++]);
	}
	printf("\n");
}


 


四、思考

前缀、中缀、后缀表达式与数的前序、中序、后序遍历十分相似,并且可以用树的结构来实现。

还没有认真学习树的实现,但是通过这里中缀到前缀的转换,这里有个疑问:树的后序遍历是否可以这样实现,首先反转树的左右节点,即同一个根节点的左节点变为右节点,右节点变为左节点,然后进行后序遍历,再逆序遍历结果?或者前序遍历也可同理得到?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值