转自:http://blog.csdn.net/hguisu/article/details/7674195
1.栈
1.1 栈的定义
栈是一种特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。如下所示:
结论:后进先出(Last In First Out),简称为LIFO线性表。
栈的基本运算有六种:
构造空栈:InitStack(S)、
判栈空: StackEmpty(S)、
判栈满: StackFull(S)、
进栈: Push(S,x)、可形象地理解为压入,这时栈中会多一个元素
退栈: Pop(S) 、 可形象地理解为弹出,弹出后栈中就无此元素了。
取栈顶元素:StackTop(S),不同与弹出,只是使用栈顶元素的值,该元素仍在栈顶不会改变。
栈的应用实例:
1、数制转换
N = (N/d)*d + N%d;如(1348)十进制=(2504)八进制
while(N)
{
Push(S, N%8);
N = N/8;
}
在将栈S依次取出就是转换后的值。
2、括号匹配的检验
如([ ][ ])或[([ ][ ])]等为正确的格式。检验括号是否匹配的方法可用“期待的急迫程度”这个概念来描述。如[([ ][ ])]分别对应的标号为12345678。
在算法中设子一个栈,每读入一个括号,若是右括号,则或者使置于栈顶的最急迫的期待得以消解,或者是不合法的情况;若是左括号,则作为一个新的更急迫的期待压入栈中,自然使原有的在栈中的所有未消解的期待的急迫性都降了一级。另外在算法的开始和结束时,栈都应该是空的。
3、行编辑程序
允许用户输入出错,并在发现有误时可以及时更正。例如,当用户发现刚刚键入的一个字符是错的时候,可以补一个退格符“#”,以表示前一个字符无效;如果发现当前键入的行内差错较多或难以补救,则可以键入一个退行符“@”,以表示当前行中的字符均无效。如下
whli##ilr#e(s#*s)
outcha@putchar(*s=#++);
则实际有效的是下列两行:
while(*s)
putchar(*s++);
为此,可设这个输入缓冲区为一个栈结构,每当从终端接受了一个字符之后先作如下判别:如果它既不是退格符也不少退行符,则将该字符压入栈顶;如果是一个退格符,则从栈顶删去一个字符;如果是一个退行符,则将字符栈清为空栈。
4、迷宫求解(穷举求解)
5、表达式求值
由于栈也是线性表,因此线性表的存储结构对栈也适用,通常栈有顺序栈和链栈两种存储结构,这两种存储结构的不同,则使得实现栈的基本运算的算法也有所不同。
我们要了解的是,在顺序栈中有"上溢"和"下溢"的概念。顺序栈好比一个盒子,我们在里头放了一叠书,当我们要用书的话只能从第一本开始拿(你会把盒子翻过来吗?真聪明^^),那么当我们把书本放到这个栈中超过盒子的顶部时就放不下了(叠上去的不算,哼哼),这时就是"上溢","上溢"也就是栈顶指针指出栈的外面,显然是出错了。反之,当栈中已没有书时,我们再去拿,看看没书,把盒子拎起来看看盒底,还是没有,这就是"下溢"。"下溢"本身可以表示栈为空栈,因此可以用它来作为控制转移的条件。
链栈则没有上溢的限制,它就象是一条一头固定的链子,可以在活动的一头自由地增加链环(结点)而不会溢出,链栈不需要在头部附加头结点,因为栈都是在头部进行操作的,如果加了头结点,等于要在头结点之后的结点进行操作,反而使算法更复杂,所以只要有链表的头指针就可以了。
1.2 栈的顺序存储
顺序栈的定义:
typedef struct{
SElemType *base;
SElemType *top;
int stacksize;
}SqStack;
其中stacksize指示栈的当前可使用的最大容量。栈的初始化操作为:按设定的初始化分配量进行第一次存储分配,base可称为栈底指针,在顺序栈中,它始终指向栈底的位置,若base的值为NULL,则表明栈结构不存在。称top为栈顶指针,其初值指向栈底,即top=base可作为栈空的标记,每当插入新的栈顶元素时,指针top增1;删除栈顶元素时,指针top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上。
使用c++的面向对象封装:
- // Test.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <iostream>
- using namespace std;
- #define MAX 10 // MAXIMUM STACK CONTENT
- class stack
- {
- private:
- int arr[MAX];
- int top;
- public:
- stack()
- {
- inItStack();
- }
- /************************************************************************/
- /* 初始化栈 */
- /************************************************************************/
- void inItStack()
- {
- top=-1;
- }
- /************************************************************************/
- /* 入栈 */
- /************************************************************************/
- void push(int a)
- {
- top++;
- if(top < MAX) {
- arr[top]=a;
- } else {
- top--;
- cout<<"STACK FULL!!"<<top;
- }
- }
- /************************************************************************/
- /* 出栈 */
- /************************************************************************/
- int pop()
- {
- if(isEmpty()) {
- cout<<"STACK IS EMPTY ";
- return NULL;
- } else {
- int data=arr[top];
- arr[top]=NULL;
- top--;
- return data;
- }
- }
- /************************************************************************/
- /* 是否为空 */
- /************************************************************************/
- bool isEmpty()
- {
- if(top == -1) return true;
- else return false;
- }
- };
- int main()
- {
- Stack a;
a.Push(1);
a.Push(2);
a.Push(3);
a.Push(4);
a.Push(5);
a.Push(6);
a.Push(7);
a.Push(8);
a.Push(9);
a.Push(10);
a.Push(11);
std::cout<<"Pop is:"<<a.Pop()<<std::endl;
a.Push(11);
std::cout<<"Pop is:"<<a.Pop()<<std::endl; - return 0;
- }
- //顺序栈
- #include <stdio.h>
- #include <stdlib.h>
- #define OK 1
- #define ERROR 0
- #define OVERFLOW -2
- #define STACKINITSIZE 100//初始化空间分配量
- #define STACKINCREASEMENT 10//分配增量
- typedef char elemType;//元素类型
- typedef struct
- {
- elemType *top;
- elemType *base;
- int stacksize;
- }SqStack;
- //初始化栈
- int InitStack(SqStack *s)
- {
- s->base=(elemType *)malloc(STACKINITSIZE*sizeof(elemType));
- if(!s->base) exit(OVERFLOW);
- s->top=s->base;
- s->stacksize=STACKINITSIZE;
- return OK;
- }
- //获取栈的长度(元素个数)
- int StackLength(SqStack *s)
- {
- int length=0;
- elemType *p=s->base;
- while(p!=s->top)//自下朝上增加
- {
- p++;
- length++;
- }
- return length;
- }
- //获取栈的长度(元素个数),另一种方法
- void GetLength(SqStack *s)
- {
- printf("栈的元素个数为%d\n",s->top-s->base);
- }
- //遍历栈,自顶向下
- int StackTraverse(SqStack *s)
- {
- elemType *p=s->top;
- printf("该栈自顶向下的元素为:\n");
- while(p!=s->base)
- {
- p--;
- printf("%c",*p);
- }
- printf("\n");
- return OK;
- }
- //获取栈顶元素
- int GetTop(SqStack *s)
- {
- if(s->top==s->base)
- printf("栈为空\n");
- return ERROR;
- printf("%c",*(s->top-1));
- return OK;
- }
- //插入值为e的栈顶元素
- int Push(SqStack *s,elemType e)
- {
- if(s->top-s->base==s->stacksize)//栈满,插入栈顶元素需要重新分配空间
- {
- s->base=(elemType *)realloc(s->base,(s->stacksize+STACKINCREASEMENT)*sizeof(elemType));
- if(!s->base) exit(OVERFLOW);
- s->top=s->base+STACKINCREASEMENT;
- }
- //*(s->top++)=e;
- *(s->top)=e;
- s->top++;//top指向栈顶元素的上方,先赋值,再top++
- return OK;
- }
- //删除栈顶元素
- int Pop(SqStack *s)
- {
- if(s->base==s->top)
- {
- printf("栈为空\n");
- return ERROR;
- }
- //printf("已删除栈顶元素 %c\n",*(--s->top));
- s->top--;
- printf("已删除栈顶元素 %c\n",*(s->top));//top指向栈顶元素的上方,先top--,再输出值
- return OK;
- }
- //判断栈是否为空
- void StackEmpty(SqStack *s)
- {
- if(s->top==s->base)
- printf("该栈为空\n");
- else
- printf("该栈不为空\n");
- }
- //清空栈
- int ClearStack(SqStack *s)
- {
- if(s->base==s->top)
- printf("栈已经为空\n");
- else
- {s->top = s->base;
- printf("栈已经被清空\n");
- }
- return OK;
- }
- main()
- {
- SqStack *s=(SqStack*)malloc(sizeof(SqStack));
- InitStack(s);
- StackEmpty(s);
- printf("插入栈顶元素...\n");
- Push(s,'a');
- Push(s,'b');
- Push(s,'c');
- Push(s,'d');
- StackEmpty(s);
- StackTraverse(s);
- printf("栈的元素个数为%d\n",StackLength(s));
- //GetLength(s);
- Pop(s);
- StackTraverse(s);
- //printf("栈的元素个数为%d\n",StackLength(s));
- GetLength(s);
- ClearStack(s);
- StackEmpty(s);
- printf("栈的元素个数为%d\n",StackLength(s));
- //GetLength(s);
- }
1.3 栈的链式存储
若是栈中元素的数目变化范围较大或不清楚栈元素的数目,就应该考虑使用链式存储结构。人们将用链式存储结构表示的栈称作"链栈"。链栈通常用一个无头结点的单链表表示。如图所示:
栈的操作是线性表操作的特例。
简单用c实现:
- // Test.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <stdio.h>
- #include "stdlib.h"
- #include <iostream>
- using namespace std;
- //宏定义
- #define TRUE 1
- #define FALSE 0
- #define OK 1
- #define ERROR 0
- #define INFEASIBLE -1
- #define OVERFLOW -2
- #define STACKEMPTY -3
- #define LT(a,b) ((a)<(b))
- #define N = 100
- typedef int Status;
- typedef int ElemType;
- typedef struct LNode{
- ElemType data;
- struct LNode *next;
- }LNode, *LinkList;
- typedef struct stack{
- LinkList top;
- } STACK;
- /************************************************************************/
- /* 接口:
- */
- /************************************************************************/
- void InitStack(STACK &S);
- void Push(STACK &S,ElemType e);
- void Pop(STACK &S, ElemType *e);
- ElemType GetTop(STACK S,ElemType *e);
- int StackEmpty(STACK S);
- /************************************************************************/
- /*
- */
- /************************************************************************/
- void InitStack(STACK &S)
- {
- S.top=NULL;
- }
- /************************************************************************/
- /* 入栈
- */
- /************************************************************************/
- void Push(STACK &S,ElemType e)
- {
- LinkList p;
- p = (LinkList )malloc(sizeof(LNode));
- if (!p) exit(OVERFLOW);
- p->data = e;
- p->next = S.top;
- S.top = p;
- }
- /************************************************************************/
- /* 出栈
- */
- /************************************************************************/
- void Pop(STACK &S, ElemType *e)
- {
- LinkList p;
- if(StackEmpty(S)) exit(STACKEMPTY);
- *e = S.top->data;
- p = S.top;
- S.top = p->next;
- free(p);
- }
- /************************************************************************/
- /* 获取栈顶元素内容
- */
- /************************************************************************/
- ElemType GetTop(STACK S, ElemType *e)
- {
- if(StackEmpty(S)) exit(STACKEMPTY);
- *e = S.top->data;
- }
- /************************************************************************/
- /* 判断栈S是否空
- */
- /************************************************************************/
- int StackEmpty(STACK S)
- {
- if(S.top==NULL) return TRUE;
- return FALSE;
- }
- void main()
- {
- STACK S;
- InitStack( S);
- Push(S, 3);
- Push(S, 4);
- ElemType e;
- Pop(S,&e);
- cout<<"Pop elem:"<<e;
- }
1.4 栈的应用
1) 数制转换
2)语法词法分析
3)表达式求值等
1.5 栈的递归和实现
汉诺塔的问题:
解决:
1)如果有一个盘子,直接从X移到Z即可。
2)如果有n个盘子要从X移到Z,Y作为辅助。问题可以转化为,先将上面n-1个从X移动到Y,Z作为辅助,然后将第n个从X移动到Z,最后将剩余的n-1个从Y移动到Z,X作为辅助。
完整实现代码,包括栈的实现:
- // Test.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <stdio.h>
- #include "stdlib.h"
- #include <iostream>
- using namespace std;
- //宏定义
- #define TRUE 1
- #define FALSE 0
- #define OK 1
- #define ERROR 0
- #define INFEASIBLE -1
- #define OVERFLOW -2
- #define STACKEMPTY -3
- #define LT(a,b) ((a)<(b))
- #define N = 100
- typedef int Status;
- typedef int ElemType;
- typedef struct LNode{
- ElemType data;
- struct LNode *next;
- }LNode, *LinkList;
- typedef struct stack{
- LinkList top;
- } STACK;
- /************************************************************************/
- /* 接口:
- */
- /************************************************************************/
- void InitStack(STACK &S);
- void Push(STACK &S,ElemType e);
- void Pop(STACK &S, ElemType *e);
- ElemType GetTop(STACK S,ElemType *e);
- int StackEmpty(STACK S);
- /************************************************************************/
- /*
- */
- /************************************************************************/
- void InitStack(STACK &S)
- {
- S.top=NULL;
- }
- /************************************************************************/
- /* 入栈
- */
- /************************************************************************/
- void Push(STACK &S,ElemType e)
- {
- LinkList p;
- p = (LinkList )malloc(sizeof(LNode));
- if (!p) exit(OVERFLOW);
- p->data = e;
- p->next = S.top;
- S.top = p;
- }
- /************************************************************************/
- /* 出栈
- */
- /************************************************************************/
- void Pop(STACK &S, ElemType *e)
- {
- LinkList p;
- if(StackEmpty(S)) exit(STACKEMPTY);
- *e = S.top->data;
- p = S.top;
- S.top = p->next;
- free(p);
- }
- /************************************************************************/
- /* 获取栈顶元素内容
- */
- /************************************************************************/
- ElemType GetTop(STACK S, ElemType *e)
- {
- if(StackEmpty(S)) exit(STACKEMPTY);
- *e = S.top->data;
- }
- void printStack(STACK S){
- LinkList p;
- p = S.top;
- printf("栈: ");
- while (p) {
- printf("%d ", p->data);
- p = p->next;
- }
- }
- /************************************************************************/
- /* 如果有一个盘子,直接从X移到Z即可。
- 如果有n个盘子要从X移到Z,Y作为辅助。问题可以转化为,先将上面n-1个从X移动到Y,Z作为辅助,然后将第n个从X移动到Z,最后将剩余的n-1个从Y移动到Z,X作为辅助。
- */
- /************************************************************************/
- void move(STACK &Sa,STACK &Sb)
- {
- ElemType e;
- Pop(Sa,&e);
- Push(Sb, e);
- }
- void hanoi(int n,STACK &X,STACK &Y,STACK &Z)
- {
- if(n==1) return move(X, Z); //将圆盘1号直接移到z
- hanoi(n-1,X,Z,Y); //将x上的1大n-1圆盘移到y,z做辅助塔
- move(X, Z); //将编号为n的圆盘移z
- hanoi(n-1,Y,X,Z); //将y上的1大n-1圆盘移到z,x做辅助塔
- }
- /************************************************************************/
- /* 判断栈S是否空
- */
- /************************************************************************/
- int StackEmpty(STACK S)
- {
- if(S.top==NULL) return TRUE;
- return FALSE;
- }
- void main()
- {
- STACK Sx, Sy,Sz;
- InitStack( Sx);
- InitStack( Sy);
- InitStack( Sz);
- int i, n = 10;
- for (i = 10 ; i>=1 ;i--) {
- Push(Sx, i);
- }
- printStack(Sx);
- hanoi(n, Sx,Sy,Sz);
- printStack(Sz);
- }