【数据结构】使用栈实现算法表达式中缀转后缀形式。运算符只包括+,-, *,/,以及括号。

题目:使用栈实现算法表达式中缀转后缀形式。运算符只包括+,-, *,/,以及括号。

要求:
(1)给出算法的设计思想;
(2)根据设计思想,采用C语言描述算法,关键之处给
出注释;
(3)说明你设计的算法时间复杂度。
一、算法的设计思想
1.理解为什么要转换为后缀表达式
中缀表达式便于人们的理解与计算,但后缀表达式更方便计算机的运算。
2.假设要转换的表达式为a+bc+(de+f)*g进行一个实例推理
读取到a,直接输出
读到“+”,将其放入栈中
读到b,再直接输出
此时栈和输出的情况如下:
在这里插入图片描述

紧接着读到“*”,

因为目前栈顶元素“+”的优先级比“”低,所以将“”压入栈中,成为新的栈顶。
读到c,直接输出
此时栈和输出的情况如下:
在这里插入图片描述
下一步读到“+”,因为栈顶元素“”的优先级比它高,所以弹出“”并输出,同时,栈中下一个元素“+”的优先级与目前读取到的“+”一样,所以也要弹出并输出。故此时先后输出“*”“+”输出并从栈中弹出,然后将当前读到的“+”压入栈中。
此时栈和输出的情况如下:
在这里插入图片描述
下一个读到的为“(”,它的优先级最高,所以就直接入栈。
读到d,将它直接输出。
此时栈和输出情况如下:
在这里插入图片描述
接下来读到“”,由于左括号比较特殊,只有碰到右括号才弹出,所以这时候直接将“”压入栈中。
读到e,直接输出。
此时栈和输出情况如下:
在这里插入图片描述
读到“+”,弹出“”并输出,(不输出左括号及下面的)然后将当前读取到的“+”压入栈中。
读到f,直接输出。
此时栈和输出情况:
在这里插入图片描述
接下来就读到了“)”,从栈顶向下依次将左右括号和其中间的数据弹出,此时左右括号元素中间的数据元素需要打印,而左右括号不需要打印。
在这里插入图片描述
读到“
”,由于其优先级高于当前栈顶元素“+”,所以将“”压入栈中。紧接着读到g,直接将其输出。
在这里插入图片描述
此时输入数据已经全部读完, 栈中还剩下两个操作符“
”和“+”,直接弹出并输出。
在这里插入图片描述
至此,中缀转后缀整个转换过程完成。
3.抽象出中缀表达式转后缀表达式的算法规则
(1)遇到操作数值,直接输出;
(2)遇到操作符比栈内已有操作符优先级高的,直接放入栈中,遇到左括号也将其放入栈中。
(3)如果遇到右括号,将栈中的元素弹出输出,直到遇到左括号,左括号只弹出不输出。
(4)遇到任何其他的操作符,如(“+”,“”,“(”)等,从栈中弹出输出元素直到遇到发现更低优先级的元素(或者栈为空)为止,优先级同样也弹出。弹出输出完这些元素后,再将当前遇到的操作符压入栈中。注意:“(”优先级最高,只有遇到“)”才弹出,其他情况一律不弹出。
4.核心算法思想:
(1)对声明的栈进行初始化,
(2)声明一个i对传入的字符数组进行遍历
(3)当遇到“#”时,表达式输入结束
(4)循环:
a.字符不等于“#”,进入while循环体。
b.内嵌一个循环,当字符大于等于“0”并且小于等于“9”或者字符大于等于“a”并且小于等于“z”时,即表示该字符为在0-9范围内的数字或者在a-z之间的字母,遇到数字或者字母直接输出。当前i为数字或者字母的时候直接输出,同时对i进行++操作,在这个循环里内嵌一个if判断语句(该循环的用处主要在于数字),如果下一个i属于数字范围内,继续当前循环,即直接打印出,但是如果下一个i不在数字范围内,就打印出空格然后跳出当前循环,这样也做到了当出现了多位数时采用空格间隔开。例如运算符之间有一个数据10,首先i指向1,打印出,然后下一个i指向0此时继续打印出,但再下一个i为运算符,不属于数字,就跳出当前循环,最后就打印出了一个完整的二位数10。
c.接下来如果字符等于‘)’右括号,把栈里剩余的运算符弹出并打印,直到匹配到左括号为止,这时候左括号只弹出不打印,目前匹配到的右括号也不入栈。
d.如果字符等于‘+’或者‘-’,加减优先级最低,如果栈为空,直接入栈,否则要将栈中所有的运算符都弹出栈并打印,注意遇到左括号要停止,将弹出的左括号重新进入栈中。最后将当前匹配到的“+”或者“-”放入栈中。

e.如果字符等于“
”或者“/”或者“(”,直接进入栈,因为其优先级最高。
f.如果匹配到字符等于“#”,即表示着表达式输入结束,这时候就可以跳出整个大循环。
g.最后,如果以上if分支都不满足,则不符合我们要求的表达式输入格式,打印出“输入格式错误!”语句。
(5)最后一次出栈操作。当上述的循环跳出后,如果栈不为空,即里面还有运算符,这时候直接按照栈顶到栈底的顺序将栈内的所有数据弹出打印即可。

二、描述算法

核心算法代码:

void TransForm(SqlStack *s,ElemType str[])
{
    int i=0;                   //声明一个i对字符串里的字符进行遍历
    ElemType e;              //声明一个e来存放char元素,比如接收后续弹出的字符等
    InitStack(s);                                  //对栈进行初始化
    while(str[i] != '#')             //只要字符不等于“#”就一直在循环内
    {
        while((str[i]>='0' && str[i]<='9')||(str[i]>='a' && str[i]<='z'))
        {
                               //如果是数字或者小写字母,则直接输出
            printf("%c",str[i++]);
            if(str[i]<'0' || str[i]>'9')
            //如果这里为数字,则直接打印出,这样就可以打印出多位数,且依靠下面的空格将各个数直接分隔开。
            {
                //如果不是数字,则打印空格跳出循环
                printf(" ");
            }
        }
        if(')' == str[i])                           //遇到字符为右括号
        {
            Pop(s,&e);                      //把栈里剩余的运算符弹出
            while('(' != e )                     //直到匹配到左括号位置
            {
                printf("%c ",e);                         //打印运算符
                Pop(s,&e);                //循环弹出栈里的剩余运算符
            }
        }

        else if('+'==str[i] || '-'==str[i])                  //加减优先级最低
        {
            if(!StackLen(s))       //如果栈为空栈,即加减号可以直接入栈
            {
                Push(s,str[i]);
            }
            Else                                         //栈不为空
            {
                do
                {
                    Pop(s,&e);              //将所有的运算符都弹出栈
                    if('('==e)
                    {
                        Push(s,e);//遇到左括号就停止,且将弹出的左括号重新入栈
                    }
                    else
                    {
                        printf("%c ",e);     //将弹出栈的元素打印出来
                    }
                }
                while(StackLen(s) && '('!=e); //最后要将当前匹配到的加号或者减号放入站内
                Push(s,str[i]);
            }
        }

        else if('*'==str[i] || '/'==str[i] || '('==str[i])
        {
            Push(s,str[i]);       //乘除和左括号,直接入栈,优先级最高
        }
        else if('#'==str[i])     //“#”表示输入结束,直接跳出当前大循环
        {
            break;
        }
        else              //不符合上述任何情况,打印格式出错提示语句
        {
            printf("\n出错:输入格式错误!\n");
            exit(0);
        }
        i++;                                 //进行下一个元素的遍历
    }
    //最后一次出栈输出
    while(StackLen(s))                 //上述循环结束后,如果栈不为空
    {
        Pop(s,&e);                            //直接将栈内的元素弹出
        printf("%c ",e);                             //打印弹出的元素
    }
}

三、算法时间复杂度
在上述的核心代码中,第一个while循环里,里面有很多分支,都是在满足特定条件的情况下才执行,而“i++”这条语句,除了最后结束的符号为“#”,在其他情况下,都要执行,循环一次执行一次,也是嵌套在循环里最深的语句,而“i++”语句的执行次数与我们从键盘端输入进行的字符串长度(含#)有关,例如我们输入“1+2+3#”,这条字符串的长度为6,而第一步i被初始化为0,接下来执行5次,等于“#”时跳出循环。
从上述推理可以得出,当输入的字符串长度为n(含#),“i++”语句执行次数T(n)=n-1.
即可以得到算法时间复杂度为O(n)。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮你实现这个功能。你需要使用一个算法来将中缀表达式换为后缀表达式,然后使用来计算后缀表达式的值。 以下是实现该功能的 Python 代码示例: ```python def calculate(expression): # 将中缀表达式换为后缀表达式 postfix_expression = infix_to_postfix(expression) # 使用计算后缀表达式的值 stack = [] for token in postfix_expression: if token.isdigit(): stack.append(int(token)) else: operand2 = stack.pop() operand1 = stack.pop() result = perform_operation(operand1, operand2, token) stack.append(result) return stack.pop() def infix_to_postfix(expression): precedence = {'+': 1, '-': 1, '*': 2, '/': 2} stack = [] postfix_expression = [] for token in expression: if token.isdigit() or token == '-': postfix_expression.append(token) elif token == '(': stack.append(token) elif token == ')': while stack[-1] != '(': postfix_expression.append(stack.pop()) stack.pop() else: while stack and stack[-1] != '(' and precedence[token] <= precedence[stack[-1]]: postfix_expression.append(stack.pop()) stack.append(token) while stack: postfix_expression.append(stack.pop()) return postfix_expression def perform_operation(operand1, operand2, operator): if operator == '+': return operand1 + operand2 elif operator == '-': return operand1 - operand2 elif operator == '*': return operand1 * operand2 elif operator == '/': return operand1 // operand2 ``` 你可以将以上代码保存为一个名为 `calculator.py` 的文件中,然后在命令行中输入以下命令来运行程序: ``` python calculator.py ``` 程序会提示你输入一个算术表达式,你可以输入任意合法的算术表达式包括负数和括号。程序将会输出该表达式的计算结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值