關於中綴轉後綴表達式的樹型算法

將近兩個月沒刷題,編程真是一點手感都沒了。昨天晚上找了這個題,雖然原來用棧做過計算器,但是這次還是花了大概3個小時來做。編程還是得多練啊。


此題是NYOJ第257題。


一開始拿到題目。我首先就是想按照棧來做。但是自己試着寫了一下,但是貌似不能用計算器的那種算完式子然後入棧的方法寫。本來準備網上搜解法的,但是一想到大二那種學習方法。還是犟着自己思考,然後就想到了嚴蔚敏書上的樹型表達式,後綴表達式就是樹的後序遍歷。於是將兩個測試畫了一下,一開始還沒發現什麼具體的規律,但是畫了兩三個之後發現樹根一直都是+或者-。似乎優先級越高的操作符越接近葉子,而所有葉子結點都是數字。在+ -兩個運算的兩邊都可以是數字或者是一個表達式。但是右邊的表達式優先級一定比根結點高。然後估計是不是可以用分治的方法,將左右兩棵子樹遞歸的來寫。就報着這個想法開始寫了。


剛開始我還沒怎麼考慮括號的情況,但後來邊寫邊想就想明白了。我的算法是:


1.如果開始的字符是單個數字,並且後面不存在操作符。那麼直接生成結點並賦值。否則跳到步驟3。
2.如果開始遇到左括號,且最後一個字符是右括號。除去括號,繼續遞歸生成二叉樹。否則那麼繼續步驟3。
3.找到最右邊優先級最低的操作符。生成一個結點,並且將符號放入數據區。括號內的整體當作一個數來看暫時不管。
4.然後分別將左右兩邊的串,分別遞歸的計算。

這是很典型的分治算法了。其要點就兩點:
1.找到優先級最低且在最右的操作符。

2.將左右兩邊式子看作子樹,遞歸運算得出結果。

開始的時候沒有考慮到多重括號的情況RE了幾次。然後自己是試着寫了個嵌套很多個的式子,問題就暴露出來了。以後還是得多想想可能的陷阱數據後再寫代碼吧。

代碼如下:

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

typedef struct asd
{	int a;
	int flag;
	struct asd * left;
	struct asd *right;
}node;


void translate(char s[],int length,node **head)
{	
	int i;
	int flag=0;
	int max;
	int kuohao;

	if(s[0]>='0'&&s[0]<='9')
	{
		
		for(i=0;i<length;i++)//如果需要遞歸計算子式
			if(!(s[i]>='0'&&s[i]<='9'))
				break;

		if(i==length)//如果只是一個數字
		{	*head=(node*)malloc(sizeof(node));
			(*head)->a=atoi(s);
			(*head)->flag=1;
			(*head)->left=NULL;
			(*head)->right=NULL;
			return ;
		}
	}
	if(s[0]=='('&&s[length-1]==')')//當式子只有一個整體的括號的時候
	{
			translate(&s[1],length-2,head);
			return;
	}

	for(i=length-1,flag=0;i>=0;i--)//找符號位置
	{	
		if(s[i]=='+'||s[i]=='-')//找到最合適的符號。
		{
			max=i;		
			break;
		}
		else if(flag==0&&(s[i]=='/'||s[i]=='*'||s[i]=='('))//
		{		max=i;
				flag=1;//用於標識只存在*/的式子
		}
		else if(s[i]=='/'||s[i]=='*'||s[i]=='(')
			continue;		

		else if(s[i]==')')
		{	kuohao=1;
			i--;
			while(kuohao!=0)//爲了保證多重括號嵌套的情況,簡單的模擬了一個括號匹配的過程
			{	if(s[i]==')')
					kuohao++;
				if(s[i]=='(')
					kuohao--;
				i--;
			}
			i++;
		}
	}

		*head=(node *)malloc(sizeof(node));//寫入符號
		(*head)->a=s[max];
		(*head)->flag=0;
		translate(s,max,&((*head)->left));//遞歸計算左子樹	
		translate(&s[max+1],length-max-1,&((*head)->right));//遞歸計算右子樹
	
}

void houxu(node *head)//後序遍歷整棵樹
{	if(head==NULL)
		return;
	houxu(head->left);
	houxu(head->right);
	if(head->flag==1)
		printf("%d",head->a);
	else
		printf("%c",head->a);
}

int main()
{
	int t;
	char get[1010];
	node *head;
	freopen("test.txt","r",stdin);
	scanf("%d",&t);
	while(t--)
	{	scanf("%s",get);
		translate(get,strlen(get),&head);
		houxu(head);
		printf("\n");
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章