中綴轉字尾——逆波蘭表示
計算機無法識別數學表示式中的括號以及四則運算的先後順序,因此需要把數學表達示轉換成一種計算機能識別的,逆波蘭表示就能很好的解決這個問題。逆波蘭表示是數學表示式中的一種不需要括號的字尾表達法。即把一箇中綴數學表示式改變成一個字尾表示。中綴表示的意思就是運算子在要計算的數字中間,而後綴表示就是運算子在要計算的數字之後。
例如:9+(3-1)*3+6/2 這就是一箇中綴表示,和正常的數學表示式一樣
931-3*+62/+ 這就是一個字尾表示
轉換規則:
1.從左到右遍歷中綴表示式的每一個數字和符號,若是數字就輸出,即成為字尾表示式的一部分;
2.若是符號,則判斷其與棧頂符號的優先順序,是右括號或優先順序不高於棧頂符號(乘除優先加減)則棧頂元素依次出棧並輸出,並將當前符號進棧,一直到最終輸出字尾表示式為止;若是左括號或者優先順序高於棧頂符號則入棧。
以上面的例子為例說明規則: (假定同一優先順序在棧內的優先順序高於棧外優先順序)
1.從左到右依次遍歷的第一個字數是9,因為是數字,不入棧,照常輸出;
2.第二個字元是+,因為是符號,同時棧內為空,則入棧;
3.第三個字元是(,因為是左括號,入棧;
4.第四個字元是3,因為是數字,不入棧,照常輸出;
5.第五個字元是-,因為其優先順序比(低,入棧;
6.第六個字元是1,因為是數字,不入棧,照常輸出;
7.第七個字元是),因為是右括號,棧中靠近棧頂的第一個左括號之後的所有元素輸出,該例中則把棧頂元素-輸出,同時棧中的左括號(出棧,但是並不輸出,右括號)也不輸出; //此時棧中就剩下字元+
8.第八個字元是*,因為其優先順序高於棧頂元素+,入棧;
9.第九個字元是3,因為是數字,不入棧,照常輸出;
10.第十個字元是+,因為其優先順序低於棧頂元素*,因此,棧頂元素*輸出,此時棧中的棧頂元素變為字元+,因為先進棧的優先順序高於後進棧(可理解為同一優先順序中棧內的優先順序高於棧外的優先順序),因此棧頂元素+輸出,此時,棧為空,字元+入棧;(當然,假如棧中還存在元素,但是其棧頂元素優先順序高於當前遍歷字元的優先順序,同樣把當前遍歷的字元入棧,如第5步;反之,繼續把棧中元素輸出,直到棧頂元素優先基高於當前遍歷的字元或者棧為空為止)
11.12.13各位看官根據我說的自己試著寫一下吧。最後結果就在上面哦。
上面所述是中綴轉字尾的具體實施步驟,根據這寫出程式碼還是有一定難度的,當然大神除外,大神的話就不需要看下面了。
程式碼的實現的難度在於怎麼去很好的區分四則運算子的優先順序,以及括號的優先順序,還有棧內棧外的優先順序。為解決這個麻煩事,作了以下假定:
棧內 數值 棧外 數值
- 4 - 3
+ 4 + 3
* 6 * 5
/ 6 / 5
( 2 ( 10
) 2
解釋下:加減的優先順序低於乘除的優先順序,且棧外的加減的優先順序低於棧內的優先順序,因此可以假設用數值3代表棧外的加減,棧內的加減的優先順序要比棧外高,因此只需要把數值加1即可,即4,同理可得乘除的,括號這比較特殊,左邊的括號在棧外時其優先順序要最大才行,因為遇到左括號就需要入棧,但是在棧中時為了能讓其他的再進來,就必須又要保證它的優先順序最小才行,右括號一遍歷到就需要把離棧頂最近的左括號上的所有元素都輸出,而且括號不要輸出,所以可以假定右括號在棧外的數值和棧中左括號值相等,當出現相等的情況時就能明白有一對括號出現。
說了一堆是不是沒看懂啊,沒關係,我現在就附上我寫的程式碼,不過我這程式碼有很大的侷限性,不過解決這個中綴轉字尾是沒什麼問題的。(侷限性就讓各位看官自己猜吧)
這是main.cpp檔案
#include"stack.h"
int main()
{
SqStack s;
char str[] = "9+(3-1)*3+6/2";
init_stack(&s); //初始化棧
mid_lat(&s, str); //中綴轉字尾
printf_s("%s\n", str);
return 0;
}
這是stack.h檔案
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 30
#define ElemType char
typedef struct
{
ElemType data[MAXSIZE];
int top;
}SqStack;
void init_stack(SqStack *s); //初始化棧
bool my_push(SqStack *s, ElemType value); //入棧
bool my_pop(SqStack *s,ElemType *p); //出棧
bool mid_lat(SqStack *s, char *p); //中綴轉字尾
int sign_fig(char *p); //符號轉換成數值
這是stack.cpp檔案
#include"stack.h"
void init_stack(SqStack *s) //初始化棧
{
assert(s);
s->top = -1; //棧為空時,即s->top=-1
}
bool my_push(SqStack *s, ElemType value) //入棧
{
assert(s);
if (s->top == MAXSIZE - 1) //棧滿
{
return false;
}
s->top++;
s->data[s->top] = value;
return true;
}
bool my_pop(SqStack *s,ElemType *p) //出棧
{
assert(s);
if (s->top == -1) //棧空
{
return false;
}
*p = s->data[s->top];
s->top--;
return true;
}
int sign_fig(char *p) //符號轉換成數值
{
assert(p);
switch (*p)
{
case '-':
case '+':return 3;
break;
case '*':
case '/':return 5;
break;
case '(':return 10;
break;
case ')':return 2;
break;
}
}
bool mid_lat(SqStack *s, char *p)
{
assert(s || p);
char *q;
char temp;
char temp_bra;
int num_out;
int num_in;
q = p;
while (*p != '\0') //遍歷表示式
{
//遍歷表示式,為數字時輸出
if (*p >= '0'&&*p <= '9' || *p == ' ') //這是程式的不足處,不足的不多寫了,害羞臉
{
*q = *p;
q++;
p++;
}
else
{
//棧為空時,棧外是符號時直接入棧
if (s->data[s->top] == -1)
{
my_push(s, *p);
p++;
}
else
{
//比較棧內棧外符號的優先順序
num_out = sign_fig(p); //棧外符號數值
temp = s->data[s->top];
if (temp == '(')
{
num_in = 2;//棧內符號數值,棧內為左括號時,數值賦為2
}
else
{
num_in = sign_fig(&temp) + 1;//棧內符號數值
}
//比較數值,確定優先順序
//棧內數值小於棧外數值時,即棧內棧頂元素的優先順序低於棧外優先順序
//則棧外元素進棧
if (num_in < num_out)
{
my_push(s, *p);
p++;
}
//棧內數值大於棧外數值時,則出棧,輸出
else if (num_in > num_out)
{
my_pop(s, q);
q++;
}
//相等時,代表出現了一對括號,棧中左括號出棧,但是不輸出
else
{
my_pop(s, &temp_bra);
p++;
}
}
}
}
while (s->top != -1) //遍歷完後,清空棧內元素,把還存在棧中的符號輸出
{
my_pop(s, q);
q++;
}
*q = '\0'; //因為是用字串來表示表示式,最後需要新增‘\0’
return true;
}