数据结构(栈的补充一)

122 阅读4分钟

(一).简单表达式求值(顺序栈)

以下三种表达式运算数的相对次序相同。

  • 运算符位于两个操作数中间的表达式称为中缀表达式exp(要考虑括号和运算符优先级)

中缀表达式的求值过程:将中缀算术表达式转换成后缀表达式;对该后缀表达式求值。

  • 运算符在操作数的前面称为前缀表达式(波兰式)

中缀转前缀:把每一对括号内的运算符提到括号前面,再把所有括号去除

后缀转前缀:把运算符前移到最近相贴的两个式子前面并括上,最后去掉所有括号

  • 运算符在操作数的后面称为后缀表达式postexp(逆波兰式)

特点:没有括号,已考虑了运算符的优先级。只有操作数和运算符,而且越放在前面的运算符来越优先执行。

中缀转后缀:把每一对括号内的运算符提到括号后面,再把所有括号去除。

后缀转中缀:把运算符前移到最近相贴的两个式子中间并括上,最后去掉所有括号

  • 两个运算符进行优先级比较
  • 遇到 ' ) ' 的情况

1.用栈实现表达式转换

  • 中缀转后缀

 从左到右扫描,如果遇到操作数就直接从左往右写出来,如果遇到运算符就入栈(入栈前要按归纳做)

归纳1: 在扫描 exp 遇到一个运算符op时,如果栈为空,直接将其进栈;如果栈不空,只有当op的优先级高于栈顶运算符的优先级时才直接将op进栈(以后op先出栈表示先执行它);否则依次出栈运算符并存入postexp(出栈的运算符都比op先执行),直到栈顶运算符的优先级小于op的优先级为止,然后再将op进栈。

归纳2: 在扫描 exp 遇到一个运算符op时,如果op为' ( ',表示一个子表达式的开始,直接将其进栈;如果op为' ) ',表示一个子表达式的结束,需要出栈运算符并存入postexp,直到栈顶为'(',再将'('出栈(左右括号都去掉,一个右括号只能消去一个左括号);如果op是其他运算符,而栈顶为'(',直接将其进栈。

void infixToPostFix(char infix[],char s2[], int &top2
{
    char s1[maxSize]; int top1 = -1; 
    int i= 0;
    while(infix[i] != '\0')
    {
        if('0' <= infix[i] && infix[i] <= '9')
        {
            s2[++top2] = infix[i];
            ++i;
        }
        else if (infix[i] == '(')
        {
            s1[++top1] = '(';
            ++i;
        }
        else if (infix[i] == '+' ||
                 infix[i] == '-' ||
                 infix[i] == '*' ||
                 infix[i] == '/' )
        {
            if (top1 == -1 ||
                s1[top1] == '(' ||
                getPriority(infix[i])> getPriority(s1[top1]))
            {
                s1[++topl] = infix[i];	
                ++i;
            }
            else
                s2[++top2]= s1[top1--];
        }
        else if (infix[i]=')')
        {
            while (s1[top1] != '(' )
                s2[++top2] = s1 [top1--]; 
            --top1;
            ++i;
        }
    }
    while (topl != -1)
        s2[++top2] = s1[top1--];
}
  • 中缀转前缀

从右到左扫描,如果遇到操作数就直接从右往左写出来,如果遇到运算符就入栈(入栈前要按反归纳做,即小于栈顶优先级就出栈)

float calInfix(char exp[])
{
    float s1[maxSize]; int top1 =-1; 
    char s2[maxSize]; int top2=-1; 
    int i=0;
    while(exp[i] != '\0')
    {	
        if ('0' <= exp[i] && exp[i] <= '9')	
        {
            s1[++top1]= exp[i] -'0';
            ++i;
        }
        else if (exp[i] == '(')
       	{
            s2[++top2]= '('; 
            ++i;	
        }
        else if (exp[i]=='+'||
                 exp[i]=='-'||
                 exp[i] =='*'||
                 exp[i] =='/')
        {	
            if (top2 == -1 ||
        	    s2[top2] == '('||
                getPriority (exp[i])>getPriority(s2[top2]))
            {
                s2[++top2] = exp[i];
                ++i;
            }
            else
            {
                int flag = calstackTopTwo(s1, top1, s2,top2); 
                if (flag ==0)
                    return 0;
            }
        }
        else if (exp[i] == ')')
        {	
            while (s2[top2] !='(')	
            {
               	int flag = calStackTopTwo(s1,topl, s2, top2);	
                if (flag ==0)
                return 0;
            }
            --top2;
            ++i;
        }
    }
    while (top2 != -1)
    {
        int flag = calStackTopTwo(sl, top1,s2,top2); 
        if (flag ==0)
            return 0;
    }
    return s1[top1];
}
  • 后缀转前缀

从左往右扫描,遇到运算符就放在两个相贴式子的前面组成一个新式子(若仅一个运算符进往左放,操作数则往右放;若几个相贴的运算符进,操作数往运算符中间放),全在入栈进行无出栈(包括操作数)。概括起来就是每次扫描到一个运算符的时候就把这个运算符所对应的两个子表达式移到运算符的后面就行了,这个移动的过程通过一个栈来实现。