[棧] 表達式相關問題代碼(C語言)-計算中綴、後綴、前綴表達式|中綴轉後綴、前綴表達式

本文內容:C語言實現並附有相關講解

  1. 計算中綴表達式
  2. 計算後綴表達式
  3. 計算前綴表達式
  4. 中綴轉後綴表達式
  5. 中綴轉前綴表達式

相關鏈接:

  1. 表達式求值彙總
  2. 多位數表達求值

【例子】

表達式 例子
表達式(中綴) 23+(76/5)22*3+(7-6/5)*2
前綴 +237/652+*23*-7/652
後綴 23765/2+23*765/-2*+

【計算結果】
在這裏插入圖片描述

【代碼】

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

// 計算
float Cal(float a, char op, float b) {
	switch (op) {
	case '+' : return (a+b);
	case '-' : return (a-b);
	case '*' : return (a*b);
	case '/' : return (a/b);
	}
	return 0;
}


/*-----------------------
 |計算中綴表達式        |
 -----------------------*/
/*
數據結構:兩個棧,一個存放操作數(stack1),一個存放運算符(stack2)
操作步驟:
1. 從左到右掃描中綴表達式
	若是數字,直接入stack1
	若是字符:
		若運算符棧爲空,直接入棧stack2
		若棧不爲空,則要與stack2的棧頂的優先級進行比較
			若當前字符爲左括號,則壓入stack2棧中
			若當前字符爲右括號,則從stack2中取出運算符,再從stack1棧中取出兩個數字進行運算,運算結果壓入stack1中;直到棧頂元素爲左括號,將左括號彈出即可(即右括號與左括號做抵消)
			若當前字符的優先級小於棧頂,則將棧頂元素拋出,從操作數棧中取兩個數字進行運算,運算結果壓入操作數棧。繼續判斷此字符與棧頂元素優先級大小,直到棧頂元素優先級小於此字符
			若當前字符的優先級大於棧頂,則將此字符直接壓入運算符棧中
2. 最後,若棧中還有元素,取出繼續計算
函數:
1. CalInfix(str[]):傳入中綴表達式,返回計算結果
2. Cal_from_stack12:上述步驟中,重複的操作即是從stack1中取操作數,stack2中取運算符進行運算,最後將結果壓入stack1中。因此將這些操作封裝成函數簡化代碼,增加可讀性
*/
float Cal_from_stack12(float stack1[], int &top1, char stack2[], int &top2) {
	// stack1爲數字的棧、stack2爲運算符的棧
	// 從兩個棧中計算
	char op = stack2[top2--];
	float b = stack1[top1--];
	float a = stack1[top1--];
	float ret = Cal(a, op, b);
	stack1[++top1] = ret;
	return ret;
}
float CalInfix(char str[]) { //計算中綴表達式
	float stack1[100];	int top1=-1;  //存放數字的棧
	char stack2[100];	int top2=-1;  //存放運算符的棧
	int i;
	
	// 遍歷中綴表達式
	for (i=0; str[i]!='\0'; ++i) {
		// str[i]是數字,直接入棧,後退出此次循環
		if (str[i]<='9' && str[i]>='0') { // str[i]數字
			stack1[++top1]=(float)(str[i]-'0');
			continue;
		} 
		
		//str[i]是字符(運算符)
			// 運算符的棧爲空,直接入棧
		if (top2==-1) {
			stack2[++top2] = str[i];
			continue;
		}
			// 運算符的棧不爲空,要比較和棧頂的優先級
		if (str[i]=='+' || str[i]=='-') { // 當前運算符爲+、-,那麼比+、-、*、/優先級都小,所以要讓它們都先計算完才能入棧
			while (stack2[top2]=='+' || stack2[top2]=='-' || stack2[top2]=='*' || stack2[top2]=='/') {
				Cal_from_stack12(stack1, top1, stack2, top2); //計算
			}
			stack2[++top2]=str[i]; //運算完後,str[i]入棧
		} else if (str[i]=='*' || str[i]=='/') { // 只有*、/計算完後,才能入棧
			while (stack2[top2]=='*' || stack2[top2]=='/') {
				Cal_from_stack12(stack1, top1, stack2, top2); //計算
			}
			stack2[++top2]=str[i]; //運算完後,str[i]入棧
		} else if (str[i]=='(') { //左括號,直接入棧
			stack2[++top2]=str[i];
		} else if (str[i]==')') { //右括號,處理到把'('抵消
			while (stack2[top2]!='(') {
				Cal_from_stack12(stack1, top1, stack2, top2); //計算
			}
			top2--; //彈出左括號
		}
	}

	// 遍歷完成後,檢查棧是否計算完
	while (top2!=-1) {
		Cal_from_stack12(stack1, top1, stack2, top2); //計算
	}

	return stack1[top1]; //返回計算結果
}

/*-------------------------
 |中綴表達式 轉 前綴表達式|
 -------------------------*/
/*
數據結構:
	1. 一個棧stack:用於存運算符
	2. 一個數組tmp:用於暫時存儲輸出結果,這個結果實際是前綴表達式的逆序。即結束後,將此數組逆置就獲得了前綴表達式
算法步驟:從右至左掃描中綴表達式
若是操作數,直接輸出到tmp數組中
若是運算符,查看棧頂
	若是右括號,直接壓入棧中
	若是左括號,將棧元素彈出輸出到tmp數組中,直到抵消到棧中的右括號
	若此運算符優先級小於棧頂元素,則棧內元素出棧並輸出到tmp數組中,直到該運算符優先級大於等於棧頂元素,再將其壓入棧中
	否則,則該運算符直接入棧
最後將棧中剩餘元素輸出到tmp中,結束後,將tmp數組翻轉
*/
int infix_to_prefix(char in[], char pre[]) {
	char stack[100]; int top=-1; //用於存放運算符
	char tmp[100];   int j=0;	 //存放暫時的結果,即前綴表達式的逆序
	int i;

	for (i=strlen(in)-1; i>=0; --i) { //從右到左掃描中綴表達式
		if ('0' <= in[i] && in[i] <= '9') { //操作數,直接輸出
			tmp[j++] = in[i];
		} else if (in[i]==')') {
			stack[++top] = in[i];
		} else if (in[i]=='(') {
			while (stack[top]!=')') {
				tmp[j++] = stack[top--];
			}
			--top; //左括號出棧
		} else if (in[i]=='+' || in[i]=='-') {
			while (stack[top]=='*' || stack[top]=='/') {
				tmp[j++] = stack[top--];
			}
			stack[++top] = in[i];
		} else if (in[i]=='*' || in[i]=='/') {
			stack[++top] = in[i];
		} else {
			return 0;
		}
	}
	// 輸出剩餘東西
	while (top!=-1) {
		tmp[j++] = stack[top--];
	}
	// 逆置
	i=0;
	for (i=0, j=j-1; j>=0; ++i,--j) {
		pre[i] = tmp[j];
	}
	pre[i]='\0';
	
	return 0;
}

/*-----------------------
 |計算前綴表達式:波蘭式|
 -----------------------*/
/*從左到右遍歷前綴表達式
若遇到操作符,入棧
若遇到操作數,查看棧頂
	若棧頂是操作符,入棧;
	若棧頂是操作數,則將操作數出棧,再出棧一個操作符,進行運算,運算後繼續判斷棧頂情況,直到棧頂不是操作數或棧空再將結果入棧
*/
typedef struct{
	union{
		char op;
		float num;
	}data;
	int flag; //0爲操作數,1爲num
}StackNode; //棧的結點
float CalPrefix(char str[]) {
	// 默認:前綴表達式合法
	StackNode stack[100]; int top=-1; //用於存放操作數和操作符的棧
	char op;
	float a,result;
	int i;
	
	for (i=0; str[i]!='\0'; ++i) {
		if ('0' <= str[i] && str[i] <='9') { //數字
			if ( top==-1 || stack[top].flag!=1 ) { // 棧頂爲空 或 棧頂不是數字,直接入棧
				++top; stack[top].flag=1; stack[top].data.num = (float)(str[i]-'0'); //數字入棧
				continue; //此次循環處理結束!
			}
			
			result = (float)(str[i]-'0'); //獲得當前的數字
			while (top!=-1 && stack[top].flag==1) { // 棧頂如果是數字,一直判斷到不是數字
				a = stack[top--].data.num; //在棧中取一個操作數
				op = stack[top--].data.op; //在棧中取一個運算符
				result = Cal(a, op, result); //計算
			}
			++top; stack[top].flag=1; stack[top].data.num = result; //將此輪計算結果入棧
		} else { //操作符
			++top; stack[top].flag=0; stack[top].data.op = str[i];
		}
	}

	return stack[top].data.num;
}

/*-------------------------
 |中綴表達式 轉 後綴表達式|
 -------------------------*/
int infix_to_suffix(char in[], char suf[]) {
	char stack[100]; int top=-1; //運算符的棧
	int i, j;

	j=0; //suf[]的指針
	for (i=0; in[i]!='\0'; ++i) { //遍歷in
		// 是數字
		if ('0' <= in[i] && in[i] <= '9') {
			suf[j++] = in[i];
			continue;
		} 

		// 是符號
		if (top==-1) { //棧爲空
			stack[++top] = in[i];
			continue;
		}
		
		// 棧不爲空
		if (in[i]=='+' || in[i]=='-') {
			while (stack[top]=='+' || stack[top]=='-' || stack[top]=='*' || stack[top]=='/') {
				suf[j++] = stack[top--];
			}
			stack[++top] = in[i];
		} else if (in[i]=='*' || in[i]=='/') {
			while (stack[top]=='*' || stack[top]=='/') {
				suf[j++] = stack[top--];
			}
			stack[++top] = in[i];
		} else if (in[i]=='(') {
			stack[++top] = in[i];
		} else if (in[i]==')') {
			while (stack[top]!='(') {
				suf[j++] = stack[top--];
			}
			top--; //將棧中'('輸出
		} else {
			suf[0]='\0';
			return -1;
		}
	}
	// 輸出剩下的符號
	while (top!=-1) {
		suf[j++] = stack[top--];
	}
	suf[j]='\0';

	return 1; //轉換成功
}

/*-------------------------
 |計算後綴表達式:逆波蘭式|
 -------------------------*/
float CalSuffix(char str[]) {
	float stack[100]; int top=-1; //存放數字
	int i;
	float a,b;

	for (i=0; str[i]!='\0'; ++i) {
		if ('0' <= str[i] && str[i] <= '9') { //數字
			stack[++top]=(float)(str[i]-'0'); 
		} else { //不是數字
			b=stack[top--];
			a=stack[top--];
			stack[++top]=Cal(a, str[i], b);
		}
	}

	return stack[top];
}



/* 例子
表達式(中綴):2*3+(7-6/5)*2
前綴:			+*23*-7/652
後綴:			23*765/-2*+

  測試數據:
2*3+(7-6/5)*2
(1+2*3)/(4/3+2)+4/2-2
*/
int main() {
	char in[100], suf[100], pre[100];

	for ( ; ; ) {
		// 輸入中綴表達式
		printf("請輸入中綴表達式:\n>>> ");
		scanf("%s", in);

		// CalInfix()函數測試
		printf("[中綴表達式] %s\n", in);
		printf("\t計算結果:%lf\n", CalInfix(in) );

		// 前綴表達式
		infix_to_prefix(in, pre);
		printf("[前綴表達式] %s\n", pre);
		printf("\t計算結果:%lf\n", CalPrefix(pre) );

		// 後綴表達式
		infix_to_suffix(in, suf);
		printf("[後綴表達式] %s\n", suf);
		printf("\t計算結果:%lf\n", CalSuffix(suf) );
		
		printf("\n");
	}
	
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章