5--栈
2016-04-19 15:51
134 查看
Stack基本概念
栈是一种特殊的线性表,也就是具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。又称为后进先出LIFO(Last In First Out)或先进后出(First In First Out)线性表。定义中说在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。栈仅能在线性表的一端进行操作
栈顶(Top):允许操作的一端
栈底(Bottom):不允许操作的一端
它的特殊之处就是在与限制了这个线性表的插入和删除位置,它始终只在栈顶进行,也就是:栈顶是固定的,最先进栈的只能在栈底。
栈的插入操作,叫做进栈,也叫压栈、入栈。
栈的删除操作,叫做出栈,也叫弹栈。
Stack的常用操作
创建栈销毁栈
清空栈
进栈
出栈
获取栈顶元素
获取栈的大小
#ifndef _MY_STACK_H_ #define _MY_STACK_H_ typedef void Stack; Stack* Stack_Create(); void Stack_Destroy(Stack* stack); void Stack_Clear(Stack* stack); int Stack_Push(Stack* stack, void* item); void* Stack_Pop(Stack* stack); void* Stack_Top(Stack* stack); int Stack_Size(Stack* stack); #endif//_MY_STACK_H_
#include "stdlib.h" #include "stdio.h" #include "string.h" #include "linkstack.h" #include "linklist.h" typedef struct _tag_LinkStackNode { LinkListNode node; void *item; }TLinkStackNode; LinkStack* LinkStack_Create() { return LinkList_Create(); } void LinkStack_Destroy(LinkStack* stack) { LinkStack_Clear(stack); LinkList_Destroy(stack); return ; } void LinkStack_Clear(LinkStack* stack) { while (LinkStack_Size(stack) > 0) { LinkStack_Pop(stack); } return ; } int LinkStack_Push(LinkStack* stack, void* item) { int ret = 0; TLinkStackNode *node = (TLinkStackNode *)malloc(sizeof(TLinkStackNode)); if (node == NULL || item == NULL) { return -1; } node->item = item; ret = LinkList_Insert(stack, (LinkListNode*)node, 0); if (ret != 0) { free(node); } return ret; } void* LinkStack_Pop(LinkStack* stack) { void *ret = NULL; TLinkStackNode *node = NULL; if (stack == NULL) { return NULL; } node = (TLinkStackNode *)LinkList_Delete(stack, 0); if (node == NULL) { return NULL; } ret = node->item; //注意 释放内存不要忘记 if (node != NULL) { free(node); } return ret; } void* LinkStack_Top(LinkStack* stack) { void *ret = NULL; TLinkStackNode *node = NULL; if (stack == NULL) { return NULL; } node = (TLinkStackNode *)LinkList_Get(stack, 0); if (node == NULL) { return NULL; } ret = node->item; return ret; } int LinkStack_Size(LinkStack* stack) { return LinkList_Length(stack); }
应用1:就近匹配
几乎所有的编译器都具有检测括号是否匹配的能力如何实现编译器中的符号成对检测?
#include<stdio.h>int main()
{ int a[4][4]; int (*p)[4]; p = a[0]; return 0;
算法思路
从第一个字符开始扫描
当遇见普通字符时忽略,当遇见左符号时压入栈中
当遇见右符号时从栈中弹出栈顶符号,并进行匹配
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
结束:
成功: 所有字符扫描完毕,且栈为空
失败:匹配失败或所有字符扫描完毕但栈非空
#include "stdio.h" #include "stdlib.h" #include "linkstack.h" int isLeft(char c) { int ret = 0; switch(c) { case '<': case '(': case '[': case '{': case '\'': case '\"': ret = 1; break; default: ret = 0; break; } return ret; } int isRight(char c) { int ret = 0; switch(c) { case '>': case ')': case ']': case '}': case '\'': case '\"': ret = 1; break; default: ret = 0; break; } return ret; } int match(char left, char right) { int ret = 0; 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 = 0; break; } return ret; } int scanner(const char* code) { LinkStack* stack = LinkStack_Create(); int ret = 0; int i = 0; while( code[i] != '\0' ) { if( isLeft(code[i]) ) { LinkStack_Push(stack, (void*)(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 = 0; break; } } i++; } if( (LinkStack_Size(stack) == 0) && (code[i] == '\0') ) { printf("Succeed!\n"); ret = 1; } else { printf("Invalid code!\n"); ret = 0; } 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:中缀后缀
计算机的本质工作就是做数学运算,那计算机可以读入字符串“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
后缀表达式 ==?符合计算机运算
波兰科学家在20世纪50年代提出了一种将运算符放在数字后面的后缀表达式对应的,
我们习惯的数学表达式叫做中缀表达式===》符合人类思考习惯
实例:
5 + 4=> 5 4 +
1 + 2 * 3 => 1 2 3 * +
8 + ( 3 – 1 ) * 5 => 8 3 1 – 5 * +
中缀表达式符合人类的阅读和思维习惯
后缀表达式符合计算机的“运算习惯”
如何将中缀表达式转换成后缀表达式?
中缀转后缀算法:
遍历中缀表达式中的数字和符号
对于数字:直接输出
对于符号:
左括号:进栈
运算符号:与栈顶符号进行优先级比较
若栈顶符号优先级低:此符合进栈 (默认栈顶若是左括号,左括号优先级最低)
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出,直到匹配左括号
遍历结束:将栈中的所有符号弹出并输出
中缀转后缀
相关文章推荐
- Jenkins进阶系列之——10Publish Over SSH插件
- Reveal-加载利用全局断点
- code与html分离,PHP中模板的使用
- POI 火狐下载文件-中文文件名乱码
- centos安装redis3.0
- Android平台,利用zxing库开发扫码功能
- JavaScript中为什么null==0为false而null>=0为true
- zoj--3932--Handshakes(水题)
- [置顶] Android开发之设置应用设置全屏的两种解决方法 兼容android5.0等两种解决方法
- Github 常用代码
- swift笔记2
- Jenkins进阶系列之——09配置Linux系统ssh免密码登陆
- 超大背包问题 (折半枚举)
- Android练习项目 Mp3播放器实现(二)
- 从频率到意义:语义向量空间模型(3)(From Frequency to Meaning: Vector Space Models of Semantics)
- linux中deb怎样安装
- mysql查询重复记录数(dede)
- mysql索引优化一例
- MySQL入门很简单: 13 数据备份和还原
- 作业5 需求分析