飞鸟各投林

导航

第3天栈


通常称,栈和队列是限定插入和删除只能在表的“端点”进行的线性表。

线性表                 栈                            队列

Insert(L, i, x)     Insert(S, n+1, x)       Insert(Q, n+1, x)

1in+1

Delete(L, i)       Delete(S, n)               Delete(Q, 1)

1in

栈是限定仅在表尾进行插入或删除操作的线性表。因此,对栈来说,表尾端称为栈顶,相应地,表头端称为栈底。不含元素的空表称为空栈。    

假设栈S=(a1,a2, ,an,an 端为栈顶,a1 端为栈底。

根据栈的存储结构的不同分为顺序栈和链栈,

以下函数的实现均以顺序栈为例

算法1:栈的数据结构

1 #define  STACK_INIT_SIZE    100; 
2 #define  STACKINCREMENT   10;  
3 typedef struct {
4 SElemType  *base;    
5 SElemType  *top;  
6 int  stacksize;    
7 } SqStack;

算法2InitStack(&S)操作结果:构造一个空栈S。          

1 Status InitStack (SqStack &S)
2 {S.base=(ElemType*)malloc(STACK_INIT_SIZE* sizeof(ElemType)); 
3 if (!S.base) exit (OVERFLOW); 
4 S.top = S.base;  //栈空的条件
5 S.stacksize = STACK_INIT_SIZE;
6 return OK;}
7 栈空的条件为: S.top = =S.base

算法3:得到栈顶元素

1 Status GetTop (SqStack S, SElemType &e)
2  { // 若栈不空,用e返回其值,并返回OK
3    // 否则返回ERROR
4 if (S.top == S.base) return ERROR;
5 e = *(S.top-1);
6 return OK;

算法4:入栈

1 Status Push (SqStack &S, SElemType e) 
2 {if (S.top - S.base >= S.stacksize) {//栈满,追加存储空间
3 S.base = (ElemType *) realloc ( S.base, (S.stacksize + STACKINCREMENT) * sizeof (ElemType));
4 if (!S.base) exit (OVERFLOW); //存储分配失败
5 S.top = S.base + S.stacksize;
6 S.stacksize += STACKINCREMENT;
7 }    
8 *S.top++ = e;     return OK;
9 }

 

算法5:出栈

1 Status Pop (SqStack &S, SElemType &e) // 若栈不空,则删除S的栈顶元素,
2      // 用e返回其值,并返回OK;
3      // 否则返回ERROR
4     if (S.top == S.base) return ERROR;
5     e = *--S.top;
6 return OK;

 



栈的应用问题:

  1. 数制转换
 1 void conversion () {
 2 InitStack(S); 
 3 scanf ("%d",N);
 4 while (N) {
 5 Push(S, N % 8);
 6 N = N/8;
 7 }
 8 while (!StackEmpty(S)) {
 9 Pop(S,e);
10 printf ( "%d", e );
11 }
12 } // conversion

例二:括号匹配的检验

算法的设计思想:

1)凡出现左括弧,则进栈;

2)凡出现右括弧,首先检查栈是否空

   若栈空,则表明该“右括弧”多余,

   否则和栈顶元素比较,

   若相匹配,则“左括弧出栈” ,

   否则表明不匹配

3)表达式检验结束时,

   若栈空,则表明表达式中匹配正确,

   否则表明“左括弧”有余。

 1 Status matching(string& exp) {
 2   int state = 1;  i=0;
 3   while (i<=Length(exp) && state) {
 4      switch of exp[i] {
 5        case 左括弧:{Push(S,exp[i]); i++; break;}
 6        case 右括弧: {
 7       if(NOT StackEmpty(S)&&GetTop(S)=左括弧)
 8             {Pop(S,e); i++;}
 9           else {state = 0;}
10           break;  } }
11   if (StackEmpty(S)&&state) return OK; }

例三:行编辑程序问题

每接受一个字符即存入存储器并不恰当!

在用户输入一行的过程中,允许用户输入出差错,并在发现有误时可以及时更正。

合理的作法是:

设立一个输入缓冲区,用以接受用户输入的一行字符,然后逐行存入用户数据区,并假设“#”为退格符,“@”为退行符

 1 while (ch != EOF) { //EOF为全文结束符
 2 while (ch != EOF && ch != '\n') {
 3       switch (ch) {
 4        case '#' : Pop(S, c); break;
 5        case '@': ClearStack(S); break;// 重置S为空栈
 6        default : Push(S, ch);  break;  
 7       }
 8       ch = getchar();  // 从终端接收下一个字符    }
 9 将从栈底到栈顶的字符传送至调用过程的数据区;
10 ClearStack(S);      // 重置S为空栈
11 if (ch != EOF)  ch = getchar();}

 

例四:表达式求值

实现算符优先算法,可以使用两个工作栈。

一个称做OPTR,用来存放运算符;

另一个称做OPND,用来存放操作数或运算结果。

算法的基本思想如下:

1)首先置操作数栈为空栈,表达式起始符“#”为运算符栈的栈底元素

2)依次读入表达式中每个字符,若是操作数则进OPND栈,若是运算符,则和OPTR栈的栈顶运算符比较优先权以后作相应操作,直至整个表达式求值完毕。

如何从后缀式求值

先找运算符,再找操作数

例如:    Exp = a ´ b + (c - d / e) ´ f

前缀式:           + ´ a b ´ - c / d e f

中缀式:           a ´ b + c - d / e ´ f

后缀式:           a b ´ c d e / - f ´ +    

posted on 2016-04-11 16:01  飞鸟各投林  阅读(222)  评论(0编辑  收藏  举报