数据结构与算法(三)栈的简单应用

栈的应用十分广泛,例如之前提到的浏览器、图像或文本编辑器等等的回退操作,操作系统使用栈进行内存管理,栈还有一个很重要的应用就是在程序设计语言中实现了递归

1、进栈转换

十进制与其他进制之间的转换,通常采用除基取余法,余数需要逆序取。栈是一种后进先出的数据结构,当需要逆序操作时,我们就可以使用栈实现十进制与其他进制之间的转换,因为无法限制十进制数的大小,所以这里使用链栈。

这里代码只是实现了十进制与十进制以下进制之间的转换,十进制以上的进制因为结果含有字符,结果转换比较麻烦,非本文主要意义就不再实现。

注:代码仅提供思路。

double Digit(int number) //计算位数 
{
    double digit = 1;
    for (int i=0; i<number; i++)
        digit = digit*10;
    return digit;
}
double DecimalConversion(int decimalNumber, int other)
{
    int modNumber   = 0;//入栈或出栈的数值
    double result   = 0;//最终结果 
    LinkStackTop *s = InitStack();//初始化一个链栈 
    while (decimalNumber)//除基直到商为0 
    {
        modNumber     = decimalNumber%other;//取余 
        decimalNumber = decimalNumber/other;//除基 
        Push(s, modNumber);//余数入栈 
    }
    while (StackLength(s))
    {
        modNumber = Pop(s);//余数出栈,实现余数逆取 
        result    = result+modNumber*Digit(StackLength(s));//每一个余数乘自己的位数加到结果上 
    }
    DestroyStack(s);//销毁链栈 
    return result;
}

2、四则运算表达式求值

栈还有一个比较常见的应用:数学四则运算表达式求值。

数学四则运算的规则:先乘除,后加减,从左到右,有括号先括号。

对于计算机来说,理解数学四则运算的规则,并直接计算求值是十分困难的。这里面的困难就在:如果乘除在加减后面,但是乘除却要先运算,而加入括号后就使得运算更加复杂。

因此有一种不需要括号的后缀表达式,是数学四则运算表达式的一种新的显示方法,非常巧妙地解决了程序实现四则运算的困难。

我们通常写出来的数学表达式称为中缀表达式:9+(3-1)*3+8/2,因为所有运算符位于需要运算的两个数字的中间。

而后缀表达式就是所有运算符号位于需要运算的两个数字后面:9 3 1 - 3 * + 8 2 / +(对应上面的中缀表达式)。(3-1)*9/2+8

那么后缀表达式是如何解决中缀表达式的运算困难的呢?

后缀表达式的运算规则:

  1. 从左到右遍历整个表达式;
  2. 遇到数字就将数字入栈;
  3. 遇到运算符就将栈顶的两个数字出栈进行运算,然后将运算结果入栈;
  4. 一直到遍历结束,栈只有一个数字那就是最终结果;

那中缀表达式如何转换为后缀表达式呢?

中缀表达式转换为后缀表达式的规则:

  1. 从左到右遍历整个中缀表达式,
  2. 遇到数字就输出,即变为后缀表达式的一部分;
  3. 遇到运算符,如果是左括号就入栈;
  4. 如果是右括号就将左括号之前的元素全部出栈,变为后缀表达式的一部分(左括号也需要出栈,但是后缀表达式中无括号,所以括号不需要变成后缀表达式的一部分);
  5. 如果不是括号,判断其与栈顶符号的优先级,如果该运算符优先级低于栈顶符号的优先级,就将栈内元素全部出栈,变为后缀表达式的一部分,否则该运算符入栈。

完成四则运算表达式求值,我们需要先将输入的中缀表达式先转换为后缀表达式,再使用后缀表达式进行求值。整个过程,我们需要一直使用到栈,充分利用了栈的先进后出的特性来处理问题,理解好了整个过程也就理解了栈。这里使用数组栈或者链栈都可以,但我一直认为链栈是最好的。

注:代码仅提供思路。

/*中缀表达式转换后缀表达式*/
void ExpressionConversion(char PostfixExpression[], int length)
{
    //PostfixExpression是后缀表达式,length为后缀表达式的长度,这两个即是参数也是返回值
    char expression;//用于挨个读入中缀表达式的字符 
    char pop;       //用于记录栈每次出栈的元素 
    char top;       //用于记录当前栈顶元素 
    LinkStackTop *s = InitStack();//初始化链栈 
	
    cout<<"输入中缀表达式:"; 
    //因为使用字符挨个读入表达式,所以不识别9以上的数字 
    while (scanf("%c", &expression) != EOF) 
    {
        if (expression == '\n') break;
    	         
        if (expression >= '0' && expression <= '9') //遇到数字
            PostfixExpression[length++] = expression;  //输出数字为后缀表达式 
    	else //遇到运算符
        {
            if (expression == '(') //遇到左括号入栈 
                Push(s, expression);
            else if (expression == ')')//遇到右括号,右括号不做操作 
            {
                while (1) //左括号之前的元素全部出栈为后缀表达式
                {         //左括号也要出栈,但不为后缀表达式 
                    pop = Pop(s);
                    if (pop == '(') break;
                    PostfixExpression[length++] = pop;
                }
            }
            else //遇到加减乘除
            {
                if (StackEmpty(s)==1) //栈不为空,需要比较优先级 
                {
                    top = GetTop(s);//获取栈顶元素用于比较优先级 
                    //只有当栈顶元素为乘除,并且新运算符为加减时,新运算符优先级低于栈顶元素 
                    if ((top == '*' || top == '/') && (expression == '+' || expression == '-'))
                    {
                        //先将栈内原有元素全部出栈
                        while (StackEmpty(s)!=0)
                            PostfixExpression[length++] = Pop(s);
                        Push(s, expression);//然后新运算符入栈 
                    }
                    else //其他情况,新运算符都入栈 
                        Push(s, expression);
                }
                else //栈为空,直接入栈 
                    Push(s, expression);
            }
        }
    }
	
    //此时中缀表达式遍历完毕,就将栈内元素全部出栈 
    while (StackEmpty(s)!=0)
        PostfixExpression[length++] = Pop(s);
		
    PostfixExpression[length++] = '\0';//后缀表达式此时转换完毕 
    cout<<"转换为后缀表达式:"<<PostfixExpression<<endl;

    DestroyStack(s);//用完就销毁链栈 
}
/*后缀表达式求值*/
int ExpressionEvaluation()
{
    char PostfixExpression[100];//用于保存后缀表达式
    int length = 0;//后缀表达式的长度 
    int result = 0;//最终结果 
    LinkStackTop *s = InitStack();//初始化链栈
	
    /*中缀表达式转换为后缀表达式*/
    ExpressionConversion(PostfixExpression, length);
    cout<<"转换为后缀表达式:"<<PostfixExpression<<endl;
	
    for (int i=0; i<length; i++)
    {
        char expression = PostfixExpression[i];//用于挨个读入后缀表达式的字符 
        if (expression >= '0' && expression <= '9') //遇到数字就入栈 
            Push(s, (expression-'0'));
        else//遇到运算符
        {   //将栈顶的两个元素出栈,并进行运算,然后将结果入栈 
            int top_1 = Pop(s);
            int top_2 = Pop(s);
            if (expression == '+')
                result =  top_2 + top_1; 
            else if (expression == '-')
                result =  top_2 - top_1; 
            else if (expression == '*')
                result =  top_2 * top_1; 
            else if (expression == '/')
                result =  top_2 / top_1; 
            Push(s, result);    
        } 
    }
    result = Pop(s);//保留最后结果 
    DestroyStack(s);//用完就销毁链栈 
    return result;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值