数据结构笔记——3.堆栈

二、堆栈
引例:算术表达式求值
算术表达式由两类对象构成:
运算数:如2、3、4
运算符号:如+、-、*、/
由于在运算时,运算符号具有优先级,而计算机是按顺序进行运算,所以需要用特殊表示方法来表示算术表达式
后缀表达式:运算符号位于两个运算数之后,运算时从左向右扫描,扫描到一个运算符号时,将该运算符号前面两个运算数做对应运算

堆栈:具有一定操作约束的线性表,只在栈顶做插入、删除
插入数据:入栈(Push)
删除数据:出栈(Pop)
后入先出:Last in first out(LIFO)

堆栈的抽象数据类型描述
类型名称:堆栈
数据对象集:一个有0个或多个元素的有穷线性表
操作集:长度为MaxSize对堆栈S∈Stack,堆栈元素item∈ElementType
五种操作:
1.Stack CreateStack(int MaxSize):生成空堆栈,最大长度为MaxSize
2.int IsFull(Stack S,int MaxSize):判断堆栈S是否已满
3.int IsEmpty(Stack S):判断堆栈S是否为空
4.void Push(Stack S,ElementType item):将元素item压入堆栈
5.ElementType Pop(Stack S)删除并返回栈顶元素
Push和Pop可以穿插交替进行,可以产生不同的出栈序列,但元素的所有排列可能不一定是出栈的序列
【例】如果三个字符按ABC的顺序压入堆栈,可以产生CAB这样的序列吗?
不能,入栈时左侧在下面,出栈时上面在左侧,ABC一共有6种组合,其中五种都可以实现,CAB不能实现

堆栈的存储实现
一、堆栈的顺序存储实现
栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成
(1)声明
#define MaxSize //数组的长度
Typedef struct SNode *Stack
Struct SNode
{
ElementType Data[MaxSize]; //声明数组
Int Top; //栈顶位置
}

(2)入栈
Void Push(Stack PtrS,ElementType item) //入栈
{
if(PtrS->Top==MaxSize-1); //检查栈是否已满
{ //数组头向下,尾向上
Printf(“堆栈满”); //判断数组尾是否有元素
Return;
}
else
{
PtrS->Data[++(PtrS->Top)]=item;//加入元素,Top同时也上升
Return;
}
}

(3)出栈
ElementType(Stack PtrS)
{
If(PtrS->Top==-1)
{
Printf(“堆栈空”); //检测栈是否为空
Return ERROR;
}
Else
{
Return(PtrS->Data[PtrS->Top–]);//将出栈值取出,Top同时减1
}
}

二、堆栈的链式存储实现
栈的链式存储结构实际上是一个单向链表,叫做链栈。插入和删除只能在链栈的栈顶进行,如果用链尾作为头,指针无法对前一个节点进行操作
(1)声明
Typedef struct SNode *Stack;
Struct SNode
{
ElementType Data;
Struct SNode *Next;
};

(2)构建堆栈
Stack CreateStack()//构建一个堆栈的头节点,返回指针
{
Stack S;
S=(Stack)malloc(sizeof(struct SNode));
S->Next=NULL;
Return S;
}
(3)Push
堆栈中的Push操作实质上就是单链表的插入操作,申请一个新节点,将新节点插入栈顶(即所有节点之前)
Void Push(ElementType item,Stack S)
{
Struct SNode *TmpCell;
TmpCell=(struct SNode *)malloc(sizeof(Struct SNode));
TmpCell->Element=item;
TmpCell->Next=S->Next;
S->Next=TmpCell;
}
(4)Pop
出栈,即把栈顶的元素提取出来并且把它从栈顶删除,实质上就是单链表的头节点删除操作
ElementType Pop(Stack S)
{
Struct SNode *FirstCell;
ElementType TopElem;
If(IsEmpty(S))
{
Printf(“堆栈空”);
Return NULL;
}
Else
{
FirstCell=S->Next;
S->Next=FirstCell->Next;
TopElem=FirstCell->Element;
Free(FirstCell);
Return TopElem;
}
}

三、堆栈的应用:表达式求值
后缀表达式求值基本过程:
从左到有读入后缀表达式的各项(运算符或运算数)
运算数:入栈
运算符:从堆栈中弹出适当数量的运算数(即栈顶的两个元素),计算并将计算结果入栈
最后,栈顶的元素就是表达式的结果值

中缀表达式求值
基本策略:将中缀表达式转换尾后缀表达式
转换过程:1.运算数相对顺序不变
2.运算符号顺序发生改变
需要存储“等待中”的运算符号
需要将当前运算符号与等待中的最后一个运算符号比较 (即先将第一个运算符号记下,再将第二个运算符记下,若等待中的符号比后面一个符号运算优先级高,则进行一次运算)
若有括号,左括号进入堆栈,优先级降为最低;直到右括号进入堆栈后,将堆栈顶部的元素依次弹出,直到左括号结束
同一个优先级下,运算从左到右

中缀表达式转换为后缀表达式的方法
从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理
1.运算数:直接输出
2.左括号:压入堆栈
3.右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
4.运算符:
若优先级大于栈顶运算符时,则将它压栈
若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出,再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后再将该运算符压栈
5.若各对象处理完毕,则吧堆栈中留存的运算符一并输出

堆栈的其他应用:
函数调用及递归实现:如返回上一级
深度优先搜索
回溯算法

你可能感兴趣的:(基础专业课)