C 栈实例
就近匹配:
应用1:就近匹配
几乎所有的编译器都具有检测括号是否匹配的能力
如何实现编译器中的符号成对检测?
#include <stdio.h> int main() { int a[][]; int (*p)[]; p = a[]; return ; 算法思路
从第一个字符开始扫描
当遇见普通字符时忽略,
当遇见左符号时压入栈中
当遇见右符号时从栈中弹出栈顶符号,并进行匹配
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
结束:
成功: 所有字符扫描完毕,且栈为空
失败:匹配失败或所有字符扫描完毕但栈非空
当需要检测成对出现但又互不相邻的事物时
可以使用栈“后进先出”的特性
栈非常适合于需要“就近匹配”的场合 计算机的本质工作就是做数学运算,那计算机可以读入字符串
“ + ( - ) * + / ”并计算值吗?
#include "stdio.h"
#include "stdlib.h"
#include "linkstack.h" int isLeft(char c)
{
int ret = ; switch(c)
{
case '<':
case '(':
case '[':
case '{':
case '\'':
case '\"':
ret = ;
break;
default:
ret = ;
break;
} return ret;
} int isRight(char c)
{
int ret = ; switch(c)
{
case '>':
case ')':
case ']':
case '}':
case '\'':
case '\"':
ret = ;
break;
default:
ret = ;
break;
} return ret;
} int match(char left, char right)
{
int ret = ; switch(left)
{
case '<':
ret = (right == '>');
break;
case '(':
ret = (right == ')');
break;
case '[':
ret = (right == ']');
break;
case '{':
ret = (right == '}');
break;
case '\'':
ret = (right == '\'');
break;
case '\"':
ret = (right == '\"');
break;
default:
ret = ;
break;
} return ret;
} int scanner(const char* code)
{
LinkStack* stack = LinkStack_Create();
int ret = ;
int i = ; while( code[i] != '\0' )
{
if( isLeft(code[i]) )
{
LinkStack_Push(stack, (void*)(code + i)); //&code[i]
} if( isRight(code[i]) )
{
char* c = (char*)LinkStack_Pop(stack); if( (c == NULL) || !match(*c, code[i]) )
{
printf("%c does not match!\n", code[i]);
ret = ;
break;
}
} i++;
} if( (LinkStack_Size(stack) == ) && (code[i] == '\0') )
{
printf("Succeed!\n");
ret = ;
}
else
{
printf("Invalid code!\n");
ret = ;
} LinkStack_Destroy(stack); return ret;
} void main()
{
const char* code = "#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0; "; scanner(code);
system("pause");
return ;
}
中缀表达式和后缀表达式
应用2:中缀 后缀
计算机的本质工作就是做数学运算,那计算机可以读入字符串
“ + ( - ) * + / ”并计算值吗?
后缀表达式 ==?符合计算机运算
波兰科学家在20世纪50年代提出了一种将运算符放在数字后面的后缀表达式对应的,
我们习惯的数学表达式叫做中缀表达式===》符合人类思考习惯 实例:
+ => +
+ * => * +
+ ( – ) * => – * +
中缀表达式符合人类的阅读和思维习惯
后缀表达式符合计算机的“运算习惯”
如何将中缀表达式转换成后缀表达式?
中缀转后缀算法:
遍历中缀表达式中的数字和符号
对于数字:直接输出
对于符号:
左括号:进栈
运算符号:与栈顶符号进行优先级比较
若栈顶符号优先级低:此符合进栈 (默认栈顶若是左括号,左括号优先级最低)
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出,直到匹配左括号
遍历结束:将栈中的所有符号弹出并输出
中缀转后缀
计算机是如何基于后缀表达式计算的?
– * +
遍历后缀表达式中的数字和符号
对于数字:进栈
对于符号:
从栈中弹出右操作数
从栈中弹出左操作数
根据符号进行运算
将运算结果压入栈中
遍历结束:栈中的唯一数字为计算结果
栈的神奇!
中缀表达式是人习惯的表达方式
后缀表达式是计算机喜欢的表达方式
通过栈可以方便的将中缀形式变换为后缀形式
中缀表达式的计算过程类似程序编译运行的过程 扩展:给你一个字符串,计算结果
“ + * ( / ( * ) + )” 字符串解析
词法语法分析
优先级分析
数据结构选型===》栈还是树?
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "linkstack.h" int isNumber(char c)
{
return ('' <= c) && (c <= '');
} int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
} int isLeft(char c)
{
return (c == '(');
} int isRight(char c)
{
return (c == ')');
} int priority(char c)
{
int ret = ; if( (c == '+') || (c == '-') )
{
ret = ;
} if( (c == '*') || (c == '/') )
{
ret = ;
} return ret;
} void output(char c)
{
if( c != '\0' )
{
printf("%c", c);
}
} //
void transform(const char* exp)
{
int i = ;
LinkStack* stack = LinkStack_Create(); while( exp[i] != '\0' )
{
if( isNumber(exp[i]) )
{
output(exp[i]);
}
else if( isOperator(exp[i]) )
{
while( priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)) )
{
output((char)(int)LinkStack_Pop(stack));
} LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if( isLeft(exp[i]) )
{
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if( isRight(exp[i]) )
{
//char c = '\0';
while( !isLeft( (char)(int)LinkStack_Top(stack) ) )
{
output((char)(int)LinkStack_Pop(stack));
} LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
break;
} i++;
} while( (LinkStack_Size(stack) > ) && (exp[i] == '\0') )
{
output((char)(int)LinkStack_Pop(stack));
} LinkStack_Destroy(stack);
} int main()
{
transform("8+(3-1)*5"); printf("\n");
system("pause");
return ;
} #include <stdio.h>
#include "LinkStack.h" int isNumber3(char c)
{
return ('' <= c) && (c <= '');
} int isOperator3(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
} int value(char c)
{
return (c - '');
} int express(int left, int right, char op)
{
int ret = ; switch(op)
{
case '+':
ret = left + right;
break;
case '-':
ret = left - right;
break;
case '*':
ret = left * right;
break;
case '/':
ret = left / right;
break;
default:
break;
} return ret;
} int compute(const char* exp)
{
LinkStack* stack = LinkStack_Create();
int ret = ;
int i = ; while( exp[i] != '\0' )
{
if( isNumber3(exp[i]) )
{
LinkStack_Push(stack, (void*)value(exp[i]));
}
else if( isOperator3(exp[i]) )
{
int right = (int)LinkStack_Pop(stack);
int left = (int)LinkStack_Pop(stack);
int result = express(left, right, exp[i]); LinkStack_Push(stack, (void*)result);
}
else
{
printf("Invalid expression!");
break;
} i++;
} if( (LinkStack_Size(stack) == ) && (exp[i] == '\0') )
{
ret = (int)LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
} LinkStack_Destroy(stack); return ret;
} int main()
{
printf("8 + (3 - 1) * 5 = %d\n", compute("831-5*+"));
system("pause");
return ;
}
C 栈实例的更多相关文章
- JAVA栈实例—括号匹配
import java.util.Stack; public class test { public static void main(String[] args){ System.out.print ...
- 框架学习之Struts2(三)---OGNL和值栈
一.OGNL概述 1.1OGNL是对象图导航语言(Object-Graph Navigation Languaged)的缩写,他是一种功能强大的表达式语言,通过简单一致的表达式语法,可以存取Java对 ...
- [ SSH框架 ] Struts2框架学习之三(OGNl和ValueStack值栈学习)
一.OGNL概述 1.1 什么是OGNL OGNL的全称是对象图导航语言( object-graph Navigation Language),它是一种功能强大的开源表达式语言,使用这种表达式语言,可 ...
- C语言函数调用栈(三)
6 调用栈实例分析 本节通过代码实例分析函数调用过程中栈帧的布局.形成和消亡. 6.1 栈帧的布局 示例代码如下: //StackReg.c #include <stdio.h> //获取 ...
- OGNL与值栈
一.OGNL入门 1.什么是OGNL OGNL的全称是对象图导航语言(Object-Graph Navigation Language),它是一种功能强大的开源表达式语言.使用这种表达式语言,可以通过 ...
- 面试题:struts 值栈 有用
一. 核心部分 1. [核心试题]完成当天课堂练习 2. [多选题] 阅读如下代码中,下列哪种方式可以在页面正确迭代获取集合中的数据 (ABC) public String add(){ ValueS ...
- (转)OGNL与值栈
http://blog.csdn.net/yerenyuan_pku/article/details/67709693 OGNL的概述 什么是OGNL 据度娘所说: OGNL是Object-Graph ...
- PWN菜鸡入门之函数调用栈与栈溢出的联系
一.函数调用栈过程总结 Fig 1. 函数调用发生和结束时调用栈的变化 Fig 2. 将被调用函数的参数压入栈内 Fig 3. 将被调用函数的返回地址压入栈内 Fig 4. 将调用函数的基地址(ebp ...
- 4、OGNL与值栈
一.OGNL 1.什么是OGNL 对象导航图语言(Object Graph Navigation Language),简称OGNL,是应用于Java中的一个开源的表达式语言(Expression La ...
随机推荐
- Hibernate事务与并发问题处理(乐观锁与悲观锁)
目录 一.数据库事务的定义 二.数据库事务并发可能带来的问题 三.数据库事务隔离级别 四.使用Hibernate设置数据库隔离级别 五.使用悲观锁解决事务并发问题 六.使用乐观锁解决事务并发问题 Hi ...
- 手动启动angular
关于手动启动 angular 的问题 angular核心原理解析1:angular自启动过程 angular.element(document).ready(function() { angular. ...
- 陈正冲老师讲c语言之声明和定义的区别
什么是定义?什么是声明?它们有何区别? 举个例子: A)int i; B)extern int i;(关于extern,后面解释) 哪个是定义?哪个是声明?或者都是定义或者都是声明?我所教过的学生几乎 ...
- 【转】禁止seekbar的拖动事件
原文网址:http://blog.csdn.net/ansionnal/article/details/8229801 当然是可以的! 其实是 onTouchEvent 事件时,不让他传递事件就行了! ...
- HTML5桌面通知:notification api
1. 为什么需要HTML5的桌面通知 传统的桌面通知可以写一个div放到页面右下角自动弹出来,并通过轮询等等其他方式去获取消息并推送给用户.这种方式有个弊端就是:当我在使用京东 进行购物的时候,我是不 ...
- onAttachedToWindow () 和 onDetachedFromWindow () ; 以及更新视图的函数ondraw() 和dispatchdraw()的区别
protected void onAttachedToWindow() This is called when the view is attached to a window. At this po ...
- 嵌入式Linux USB WIFI驱动的移植
硬件平台:飞思卡尔MX258开发板 操作系统:Linux2.6.31 WIFI: RT2860 USB WIFI模组 交叉编译环境:gcc version 4.1.2 调试步骤: 第一步:测试U ...
- NGINX(四)配置解析
前言 nginx配置解析是在初始化ngx_cycle_t数据结构时,首先解析core模块,然后core模块依次解析自己的子模块. 配置解析过程 nginx调用ngx_conf_parse函数进行配置文 ...
- 安装GNS3-0.8.6-all-in-one时language里没有选项
初次安装使用GNS3,安装的版本是GNS3-0.8.6-all-in-one,本人也是菜鸟,安装时都是一路 Next,结果安装后运行出现了这样的问题,如图 language里是没有选项的,解决方法 把 ...
- e2e 自动化集成测试 架构 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step (二) 图片验证码的识别
上一篇文章讲了“e2e 自动化集成测试 架构 京东 商品搜索 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step 一 京东 商品搜索 ...