首页 > 学院 > 开发设计 > 正文

Chapter_3表、栈和队列:栈

2019-11-11 05:30:44
字体:
来源:转载
供稿:网友

1、栈模型的引进

From百度百科(修改):栈,是一种运算受限的线性表。仅允许在表的一端(栈顶)进行插入和删除运算,另一端称为栈底。 运算:Push:向栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素。 Pop:从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

如下图为模型图: 这里写图片描述 这里写图片描述

2、栈的指针链表实现

类似于链表的指针实现,栈的链表形式实现也差不多,思路比较清晰。

// _Stack_H.h#ifndef _Stack_Hstruct Node;typedef struct Node * PtrToNode;typedef PtrToNode Stack;int Isempty(Stack S);Stack CreateStack(void);// void DisposeStack(void);void MakeEmpty(Stack S);int Push(ElementType X,Stack S); /*新元素进栈操作*/ElementType Top(Stack S); /*返回栈顶元素*/int Pop(Stack S); /*栈顶元素出栈*/#endif/*Implementation of Functions*/#include <stdio.h>#include <stdlib.h>#include '_Stack_H.h'struct Node{ ElementType Element; PtrToNode Next; /* data */};/*测试栈是否为空*/int Isempty(Stack S){ return S->Next==NULL;}/*创建一个空栈,即栈初始化*/void MakeEmpty(Stack S){ if(S==NULL) { PRintf("Must use CreateStack first!!!/n"); return -1; } else while(!Isempty(S)) Pop(S);}Stack CreateStack(void){ Stack S; S=malloc(sizeof(struct Node)); if(S==NULL) { printf("Out of space!!!"); return -1; } S-Next==NULL; MakeEmpty(S); return S;}int Push(ElementType X,Stack S){ PtrToNode TmpCell; TmpCell=malloc(sizeof(struct Node)); if(TmpCell==NULL) { printf("Out of space!!!/n"); return -1; } else { TmpCell->Element=X; TmpCell->Next=S->Next; S->Next=TmpCell; return 0; }}ElementType Top(Stack S){ if(!Isempty(S)) return S->Next->Element; else printf("Empty stack!!!"); return 0; /*Return value used to avoid warning*/}int Pop(Stack S){ PtrToNode FirstCell; /*不考虑不能分配内存(即不用malloc)*/ /*改进,加入malloc*/ FirstCell=malloc(sizeof(struct Node)); if(FirstCell==NULL) { printf("Out of space!!!/n"); return -1; } if(Isempty(S)) { printf("Empty stack/n"); return -1 } else { FirstCell=S-Next; S->Next=S->Next->Next; free(FirstCell); return 0; }}

3、栈的数组实现

数组实现时,感觉相对指针的有点不习惯。声明结构体时,链表的是以包括一个元素和一个指针的节点实现的;而数组的是包括三个量:栈的容量(自定),TopOfStack(栈顶状态)以及一个数组指针(储存栈中的数据)。以下为区别:

//链表实现的结构体声明struct Node{ ElementType Element; PtrToNode Next;};//另一个不同点:设置空栈条件&栈容量最小值#define EmptyTOS (-1)#define MinStackSize (5)//数组实现的结构体声明struct StackRecord{ int capacity; int TopOfStack; ElementType * Array;}

其中TOS(TopOfStack)为栈顶在数组中的位置,且-1时表示空栈(栈下溢),如TOS=N-1(N为容量),则表示栈满了;TOS=0,表示栈只有一个元素(栈底元素)。 数组编号从栈底为0开始编号。 因此,此时处理栈就不像链表那样对节点进行处理(其实,链表中的节点等同于把Array数组每个元素分开处理),而是对整个栈(Array) 进行处理。则有如下算法规则: 这里写图片描述

截图来源于百度百科

即有: Push:先判断是否栈满。若不满,则TOS加1,令Stack[TOS]=X。若栈满,则报错。 Pop:先判断是否栈空。若不空,先弹出栈顶元素Stack(TOS),令Temp=Stack(TOS),再有TOS减1。若空,则报错。

4、栈的应用

1.平衡符号 如下为原书原话: 这里写图片描述

举个例子,对“ [ ( ] ) “进行判断。读入”[“和”(“时,为开放符号,入栈。读入”]“(右方括号),为封闭符号,此时栈不空,将栈顶”(“(左圆括号)弹出,发现不匹配,报错。 还有就是,如果读取到文件尾,栈非空也报错。

2.后缀表达式 后缀记法,也被称为逆波兰记法。一般标准表达式,如1∗2+3+5∗6,又称为中缀表达式,其对应的后缀表达式为12∗3+56∗+

(1)后缀表达式的计算 以6523+8∗+3+∗ 为例计算后缀表达式的值。利用栈计算,有以下原则

当遇到数字时,将其压栈。当遇到运算符时,将栈中栈顶两个元素弹出,进行该运算符的运算 如下为原书例子 这里写图片描述

这里写图片描述

这里写图片描述

(2)中缀到后缀的转换 对于中缀到后缀的转换,比较复杂。书中只讨论有+*() 四种运算符的情况(加号,乘号,左圆括号,右圆括号)。有如下转换原则: 首先,假设中缀表达式是合法的,即正确的。 运算符优先级有从低到高是:+*()

初始化一个空栈,读取时从左到右读取字符(因为涉及的都是从左到右运算的运算符,若像取幂运算符,则不行)当遇到数字时,不压入栈,直接输出当栈为空时,读到的第一个运算符直接压栈。(因为假设原表达式合法,即不存在右圆括号在前,左的在后的情况)当栈非空(即有运算符在里面),读到运算符A时,从栈中弹出栈元素直到发现优先级比A更低为止。左右圆括号为例外。即(要直到遇到)才出栈 其实,还是例子生动,详细例子见网站:

http://www.nowamagic.net/librarys/veda/detail/2307

这个例子较好。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表