栈
1.定义:限定仅在表尾进行插入或删除操作的线性表。
表尾:栈顶
表头:栈底
不含元素的空表称空栈。
2.特点:先进后出(FILO)或后进先出(LIFO)
3.栈的基本操作
InitStack(S) Push(S,x)
ClearStack(S) Pop(S,x)
IsEmpty(S) GetTop(S,x)
IsFull(S)
4.栈的表示和实现
栈在计算机中主要有两种基本的存储结构:
顺序存储结构--------顺序栈
链式存储结构--------链栈
5.顺序栈:利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置。
顺序栈的类型说明:
typedef struct{
ElemType elem[Stack_Size];
int top;
}SeqStack;
说明:top == -1,表示栈空;
top ==stacksize-1,表示栈满;
每插入一元素时,top加1;
每删除一元素时,top减1;
6.顺序栈的基本操作
//顺序栈的初始化
void InitStack ( SeqStack * s )
{
S->top= -1;
}
//顺序栈的判空
int IsEmpty ( SeqStack * s )
{
if ( S->top= =-1 )
return 1;
else
return 0;
}
//顺序栈的判满
int IsFull ( SeqStack * s )
{
if ( S->top = = Stack_Size-1 )
return 1;
else
return 0;
}
//顺序栈的入栈
int Push ( SeqStack *S, ElemType e )
{
if(S->top==Stack_Size-1) return FALSE;
S->top++;
S->elem[S->top]=e;
return TRUE;
}
//顺序栈的出栈
int Pop ( SeqStack *S, ElemType *e )
{
if ( S->top== -1 ) return FALSE;
*e=S->elem[S->top];
S->top--;
return TRUE;
}
//顺序栈读取栈顶元素
int GetTop ( SeqStack *s, ElemType *e )
{
if ( S->top== -1 ) return FALSE;
*e=S->elem[S->top];
return TRUE;
}
两栈共享技术
原因:若在一个程序中要同时使用多个栈,如果采用顺序存储结构,会因为栈空间大小难以准确估计,产生有的栈溢出,有的栈还很空闲的情况,故产生了两栈共享技术。
特点:栈底位置不变,而栈顶位置动态变化。
首先为两个栈申请一个共享的一段存储空间S[M],然后将两个栈的栈底分别放在存储空间的两段,分别是0,M-1。
//两栈共享的数据结构定义
#define M 100
typedef struct
{
ElemType Stack[M];
int top[2];
} DqStack;
//两栈共享的初始化
void InitStack ( DqStack *S )
{
S->top[0]=-1;
S->top[1]=M;
}
//两栈共享的入栈操作
int Push(DqStack *S, ElemType x, int i)
{ if(S->top[0]+1==S->top[1]) return(FALSE);
switch(i)
{ case 0: S->top[0]++; S->Stack[S->top[0]]=x; break;
case 1: S->top[1]--; S->Stack[S->top[1]]=x; break;
default: return(FALSE);
}
return(TRUE);
}
//两栈共享的出栈操作
int Pop(DqStack *S, ElemType *x, int i)
{ switch(i)
{ case 0: if(S->top[0]==-1) return(FALSE);
*x=S->Stack[S->top[0]]; S->top[0]--; break;
case 1: if(S->top[1]==M) return(FALSE);
*x=S->Stack[S->top[1]]; S->top[1]++; break;
default: return(FALSE);
}
return(TRUE);
}
链栈
2.链栈的结点类型
typedef struct node
{
ElemType data;
struct node *next;
}LinkStackNode, *LinkStack;
3.链栈的入栈操作
int Push(LinkStack top, ElemType x) {
temp=( )malloc(sizeof(LinkStackNode));
if(!temp) return FALSE;
temp->data=x;
temp->next=top->next;
top->next=temp; /* 修改当前栈顶指针 */
return TRUE;
}
4.链栈的出栈操作
int Pop(LinkStack top, ElemType *x) {
temp=top->next;
if(temp==NULL) return FALSE; /*栈为空*/
top->next=temp->next;
*x=temp->data;
free(temp); /* 释放存储空间 */
return TRUE;
}
栈的应用
void Conversion(int N)
{ Stack S; int x; /*S为顺序栈或链栈*/
InitStack(&S);
while(N)
{ x=N%2; Push(&S, x); N=N/2; }
while(!IsEmpty(S))
{ Pop(&S,&x); printf(“%d”,x); }
}
//十进制数转换成K进制数
void Conversion(int N,int base)
{ Stack S; int x; /*S为顺序栈或链栈*/
InitStack(&S);
while(N)
{ x=N%base; Push(&S, x); N=N/base; }
while(!IsEmpty(S))
{ Pop(&S,&x);
if(x<10) printf(“%d”,x);
else printf(“%c”,x+55); }
}
2.括号匹配问题
算法思想:
在检验算法中设置一个栈,依次读入表达式中的括号。
若读入的是左括号,则直接入栈,等待相匹配的同类右括号;
若读入的是右括号,且与当前栈顶的左括号同类型,则二者匹配,将栈顶的左括号出栈,否则属于不合法的情况。
如此反复,直到:
输入序列和栈同时变为空,说明所有括号完全匹配;
输入序列已读尽,而栈中仍有等待匹配的左括号,说明括号不匹配,表达式不合法;
或者读入了一个右括号,而栈中已无等待匹配的左括号,同样属于不合法的情况。
3.回文游戏
4.表达式求值
5.函数的调用
6.Tower of Hanoi问题
问题描述:有A,B,C三个塔座,A上套有n个直径不同的圆盘,按直径从小到达叠放,形如宝塔,编号1,2,3......n。
要求:将n个原盘从A移动到C,叠放顺序不变,移动过程中遵循下列原则:
每次只能移一个圆盘,
圆盘可在三个塔座上任意移动,
任何时刻,每个塔座上不能将大盘压到小盘上。
解决方法:
n=1时,直接把圆盘从A移到C
n>1时,先把上面n-1个圆盘从A移到B
然后将n号盘从A移到C
再将n-1个盘从B移到C
即把求解n个圆盘的Hanoi问题转化为求解n-1个圆盘的Hanoi问题,依次类推,直至转化成只有一个圆盘的Hanoi问题
//Hanoi算法
void hanoi(int n,char x,char y,char z) {
if(n==1) move(1,x,z);
else{
hanoi(n-1,x,z,y);
move(n,x,z);
hanoi(n-1,y,x,z);
}
}
void move( int n,char x,char y )
{ printf(“%d:%c%c\n”,n,x,y); }
7.迷宫问题