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 ...
随机推荐
- NOI2006最大获利
终于搞明白了…… x到y有边意味着选x必须选y,所以才会有闭合子图中一个点的后继一定也在这个闭合子图中. 接下来按照s连正权,负权连t就ok了 type node=record go,next,c:l ...
- SGU 438 The Glorious Karlutka River =) ★(动态+分层网络流)
[题意]有一条东西向流淌的河,宽为W,河中有N块石头,每块石头的坐标(Xi, Yi)和最大承受人数Ci已知.现在有M个游客在河的南岸,他们想穿越这条河流,但是每个人每次最远只能跳D米,每跳一次耗时1秒 ...
- ChineseCounter.cs 统计中文文本中常用字占比
http://www.tuicool.com/articles/qmMba2 1 using System; using System.IO; using System.Collections.Gen ...
- Clear All of Them I(HDU 3920状压dp)
题意:给有2*n个敌人的位置,枪在(0,0)位置,一次能消灭两个敌人,耗费能量为枪到一个敌人,由这个敌人再到另个敌人的的距离和,求消灭所有敌人最小耗费能量. 分析:一次枚举状态的两位即可 #inclu ...
- Linux创建公钥
A:192.168.1.1 B:192.168.1.2 现在想让A无密码登陆B机器 A上运行以下命令来生成公钥和私钥 ssh-keygen -t rsa -P '' 运行该命令后会生成如下两个文件 ...
- DNS(三)DNS SEC(域名系统安全扩展)
工作需要今天了解了下DNS SEC,现把相关内容整理如下: 一.DNS SEC 简介 域名系统安全扩展(英语:Domain Name System Security Extensions,缩写为DNS ...
- iOS程序性能优化
iOS程序性能优化 一.初级 使用ARC进行内存管理 在iOS5发布的ARC,它解决了最常见的内存泄露问题.但是值得注意的是,ARC并不能避免所有的内存泄露.使用ARC之后,工程中可能还会有内存泄露, ...
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...
- C++多线程框架-----Mutex互斥和Sem信号量
互斥和信号量是多线程编程的两个基础,其原理就不详细说了,大家去看看操作系统的书或者网上查查吧. 对于互斥的实现,无论什么操作系统都离不开三个步骤 1.初始化互斥锁 2.锁操作 3.解锁操 ...
- 题目1043:Day of Week(输入日期与当前日起天数差%7,在做相关星期调整)
题目描述: We now use the Gregorian style of dating in Russia. The leap years are years with number divis ...