【八】栈的应用实例(二)

来源:互联网 发布:淘宝双十一红包套现 编辑:程序博客网 时间:2024/05/01 08:30

1、问题的提出

尝试用计算机读入字符串“9+(3-1)*5+8/2+(5/2)”并计算值

2、中缀表达式 与 后缀表达式

波兰科学家在20世纪50年代提出了一种将运算符放在数字后面的后缀表达式
对应的,我们习惯的数学表达式叫做中缀表达式
实例:
 5 + 3 => 5 3 +
 1 + 2 * 3 => 1 2 3 * +
 9 + ( 3 – 1 ) * 5 => 9 3 1 – 5 * +

中缀表达式符合人类的阅读和思维习惯
后缀表达式符合计算机的“运算习惯”

3、将中缀表达式转换成后缀表达式?

实现思路:

  • 遍历中缀表达式中的数字和符号
  • 对于数字:直接输出 直接输出
  • 对于符号:
    • 左括号:进栈
    • 符号:与栈顶符号进行优先级比较
    • 栈顶符号优先级低:进栈
    • 栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
    • 右括号:将栈顶符号弹出并输出,直到匹配左括号
  • 遍历结束:将栈中的所有符号弹出并输出

4、实现代码

/*  中缀表达式到后缀表达式的转换  参数:    str:    指向中缀表达式的指针,传入参数    retval: 指向返回结果的后缀表达式,传出参数*/void transform(const char *str,char *retval){  LinkStack *stack = LinkStack_Create();  int i = 0,j = 0;  //判断返回数据的指针是否有效  if(retval == NULL)  {    return;  }  while(str[i] != '\0')  {    //如果是数字,直接输出它    if(isNumber(str[i]))    {      retval[j] = str[i];      j++;    }    else      if(isOperator(str[i]))      {        /*          如果是运算符,则检查栈顶符号优先级是否大于等于当前符号优先级;          如果是,则弹出栈顶运算符并输出,然后进栈当前优先级低的运算符          如果否,即栈顶的运算符优先级低,则直接进栈          特殊情况,栈中没有元素时,不用比较优先级,直接进栈        */        char *top = (char*)LinkStack_Top(stack);        if(top != NULL)        {          if(priority(*top) >= priority(str[i]))          {            retval[j] = *(char*)LinkStack_Pop(stack);            j++;          }        }        LinkStack_Push(stack,(LinkStackNode*)(str + i));      }      else        if(isLeft(str[i]))        {          //如果是左括号,直接进栈          LinkStack_Push(stack,(LinkStackNode*)(str + i));        }        else          if(isRight(str[i]))          {            /*              如果是右括号,依次弹出栈顶元素,并输出,知道匹配左括号              即是,知道栈顶弹出的是左括号为止              但是,并不输出左右括号            */            char temp = '\0';            while(!isLeft(temp))            {              if(temp != '\0')              {                retval[j] = temp;                j++;              }              temp = *(char*)LinkStack_Pop(stack);            }          }          else          {            printf("Invalid expression!");            break;          }    i++;  }  /*    如果遍历结束,并且栈中还有数据,那么依次弹出它们,并输出    这里判断str[i] == '\0' 是因为可能中缀表达式中有为止符号,    那么将使上面的循环提前终止,并没有检测完中缀表达式,即使这时候    栈中有元素,那转换还是错误的!!  */  while((LinkStack_Size(stack) > 0) && (str[i] == '\0'))  {    retval[j] = *(char*)LinkStack_Pop(stack);    j++;  }  LinkStack_Destroy(stack);}

5、对后缀表达式的计算

计算机对后缀表达式的运算也是基于栈的!

实现思路:

  • 遍历后缀表达式中的数字和符号
  • 对于数字:进栈
  • 对于符号:
    • 从栈中弹出右操作数
    • 从栈中弹出左操作数
    • 根据符号进行运算
    • 将运算结果压入栈中
  • 遍历结束:栈中的唯一数字为计算结果

6、实现代码

/*  用于计算后缀表达式的值  参数str:指向后缀表达式的指针*/DataType compute(const char *str){  LinkStack *stack = LinkStack_Create();  DataType iret = 0,i = 0;  while(str[i] != '\0')  {    //如果是数据,进栈    if(isNumber(str[i]))    {      //直接存放DataType类型数据的值      LinkStack_Push(stack,(LinkStackNode*)chartoDataType(str[i]));    }    else      if(isOperator(str[i]))      {        //如果是操作符,则依次弹出栈顶,分别为该操作符的右操作数和左操作数        DataType right = (DataType)LinkStack_Pop(stack);        DataType left = (DataType)LinkStack_Pop(stack);        //计算它们的值,然后将其压栈        DataType result = express(left,right,str[i]);        LinkStack_Push(stack,(LinkStackNode*)result);      }      else      {        printf("Invalid expression!\n");        break;      }    i++;  }  /*    运算结束,如果栈中只有一个数据,并且str[i] == '\0'    那么运算是成功的;    判断str[i] == '\0'是因为如果后缀表达式中有非运算符和数值的字符,    循环会提前结束,导致结果是不正确的  */  if(LinkStack_Size(stack) == 1 && str[i] == '\0')  {    //获取最终的结果    iret = (DataType)LinkStack_Pop(stack);  }  LinkStack_Destroy(stack);  return iret;}

7、完整源码下载

文件名:compute-1.0.tar.gz
链接: http://pan.baidu.com/s/1sjHTaMx 密码: twd5

文件名:compute-1.1.tar.gz
链接: http://pan.baidu.com/s/1hq1qFA0 密码: nufi
说明:修复了由linklist.c中的List_Get()函数所引起的BUG,详情见链接!

编译步骤:
0.1 解压缩:tar -zxvf compute-1.0.tar.gz
0.2 进入目录:./configure
0.3 生成Seqlist:make
0.4 运行程序:./Compute

0 0
原创粉丝点击