【八】栈的应用实例(二)
来源:互联网 发布:淘宝双十一红包套现 编辑:程序博客网 时间: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
- 【八】栈的应用实例(二)
- CodeSmith应用实例(二)
- jeesite快速开发平台(八)---工作流的应用实例
- vim的正则表达式(二)应用实例
- Log4J日志组件的实例应用(二)
- java集合类(八)toArray与asList应用实例
- jQuery验证框架(八)应用实例 (jQuery validation)
- NetAdvantage的WebGrid 实例应用(二)
- NetAdvantage的WebGrid 实例应用(二)
- ValueListEditor组件应用实例(二)
- PHP之cookie应用实例(二)
- WebSocket详解(二)应用实例
- activeMQ实践(二)--简单应用实例
- 栈的应用实例
- map应用实例二
- fragment应用实例二
- 栈的应用(二)
- 八、线程的同步(二)
- 关键字volatile有什么含义?并给出三个不同的例子
- 5.0侧滑菜单(仿QQ)
- libplist源码编译常见错误总结
- 查看java当前线程的堆栈信息
- IOS友盟统计Bug追踪
- 【八】栈的应用实例(二)
- 链队列的简单实现
- 如何理解c和c ++的复杂类型声明
- Android列表视图ListView和ListActivity-android学习之旅(二十四)
- MySQL更新varchar字段时的奇怪现象
- codeforces 548 C Mike and Frog
- C#Winform 中,两个form之间参数传递
- HTTP 304 Not Modified
- Java开发环境之Spring+SpringMVC+Mybatis整合demo