第二讲线性结构
2.2堆栈
堆栈的基础知识
堆栈是一种线性结构,也是一个特殊的线性表
- 堆栈的引入
例子:计算机如何进行表达式求值
5+6/2-34=5+3-34=8-12=-4- 由两类对象构成
- 运算数
- 运算符
- 不同的运算符优先级不一样
堆栈(Stack):具有一定操作约束的线性表
- 特点:只在一端(栈顶)做插入、删除
插入数据:入栈
删除数据:出栈- 后入先出
数据对象集:一个有0个或多个元素的又穷线性表
操作集:长度为MaxSize的堆栈S∈Stack,堆栈元素item∈ElementType
- 1.Stack Create(int MaxSize):生成空堆栈,其最大长度为MaxSize;
- 2.int IsFull(Stack S, int MaxSize):判断堆栈S是否已满
- 3.void Push(Stack S, ElementType item):将元素item压入堆栈
- 4.int IsEmpty(Stack S):判断堆栈是否为空
- 5.ElementType Pop(Stack S):删除并返回栈顶元素
其中Pop和Push可以同时进行==(常考查出栈顺序的可能性)==
栈的顺序存储实现
栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成
- 使用一个结构来表示堆栈
该结构包含两个分量
- Data数组,数组的分量是ElementType这个类型
- Top整型变量,指示栈顶位置的数组下标
#define MaxSize<储存数据元素的最大个数>
typedef struct SNode *Stack;
struck SNode{
ElemenrType Data[MaxSize];
int Top;
};
- 入栈
包含两个参数(堆栈本身PtrLS指针,入栈元素item)
此处用PtrLS指针来表示堆栈,PtrLS是一个Stack类型的结构指针
void Push(Stack PtrS, ElementType item)
{
if(PtrS->Top==MaxSize-1){ //因为数组分量下标是从0开始
print("堆栈满");
return;
}else{
PtrS->Data[++(PtrL->Top)]=item;//item放在top上面的一个位置,所以
//①把item放在top+1的位置②把top+1
return;
}
}
- 出栈
ElementType Pop(Stack PtrS)
{
if(PtrS->Top==-1){
printf("堆栈空");
return ERROR;//ERROR是ElementType的特殊值,标志错误
}else{
return (PtrS->Data[(PtrS->Top--)]);//①return下标为top的位置的值②把top值-1
}
}
- 两个堆栈的结构
- 例子:请用一个数组实现两个堆栈,要求最大地利用数组空间,使数组只要由空间,入栈操作就可以成功
分析:一种比较聪明的方法是使这两个栈分别从数组两头开始向中间生长;当两个栈的栈顶指针相遇时,表示两个栈都满了
两个堆栈的结构
#define MaxSize<数组数据元素的最大个数>
struct DStack{
ElementType Data[MaxSize];
int Top1; //堆栈1的栈顶指针
int Top2; //堆栈2的栈顶指针
}S;
S.Top1=-1;
S.Top2=MaxSize;
1.Push操作
//1.Push操作
void Push(struct DStack *PtrS, ElementType itme ,int Tag)
{
if(Ptrs->Top2 - PtrS->Top1==1){ //两个堆栈的top挨在一起
printf("堆栈满");
return;
}
if(Tag==1){ //对第一个堆栈操作
PtrS->Data[++(PtrS->Top1)]=item; //把item放到top1的后面一个位置
}else{ //对第一个堆栈操作
PtrS->Data[--(PtrS->Top2)]=item; //把item放到top2的前面一个位置
}
}
2.Pop操作
//2.Pop操作
ElementType Pop(struct DStack *PtrS, int Tag)
{
if(Tag==1){ //对第一个堆栈操作
if(PtrS->Top==-1){ //堆栈1空
printf("堆栈1空");
return NULL;
}else{
return PtrS->Data[(PtrS-<Top)--];
}
}else{ //对第二个堆栈操作
if(PtrS->Top2==MaxSize){ //堆栈2空
printf("堆栈2空");
return NULL;
}else{
return PtrS->Data[(PtrS->Top2)++];
}
}
}
栈的链式存储实现
- 堆栈的结构
typedef struct SNode *Stack;
struct SNode{
ElementType Data;
struct SNode *Next;
};
- 堆栈的初始化
Stack CreateStack()
{
Stack S;
s=(Stack)malloc(sizeof(struct SNode));
S->Next=NULL;
return S;
}
- 判断堆栈S是否为空
int IsEmpty(Stack S)
{ //判断堆栈S是否为空,若为空函数则返回整数1,否则返回0
return (S->Next==NULL);
}
- Push操作
void Push()
{
struct SNode *TmpCell;
TmpCell=(struct SNode*)malloc(sizeof(struct SNode));//申请一块内存
TmpCell->Element=item; //把item的值写入节点
TmpCell->Next=S->Next; //把下一个元素的指针赋值给新插入的元素的指针
S->Next=TmpCell; //把新插入的内容赋值给上一个节点的指针,让指针指向新插入的内容
}
- Pop操作
ElementType Pop(Stack S)
{
struct SNode *FirstCell;
ElementType TopElem;
if(IsEmpty(S)){
printf("堆栈空");
return NULL;
}else{
FisrtCell=s->Next;
S->Next=FirstCell->Next;
TopElem=FirstCell->Next;
free(FirstCell);
return TopElem;
}
}
堆栈的应用
- 中缀表达式
基本策略:将中缀表达式转换为后缀表达式,然后求值
观察两个个简单的例子
1.2+9/3-5 --> 2 9 3 / + 5 -
- 1.运算数相对顺序不变
- 2.运算符号顺序发生改变
- 需要存储”等待中“的运算符号
- 需要将当前运算符号与”等待中的“最后一个运算符号比较
2.a*(b+c)/d --> a b c + * d /
堆栈的其它应用
- 函数调用及递归实现
- 深度优先搜索
- 回溯算法