本文数据结构讲解参考书目:
通过网盘分享的文件:数据结构 C语言版.pdf
链接: https://pan.baidu.com/s/159y_QTbXqpMhNCNP_Fls9g?pwd=ze8e 提取码: ze8e
数据结构基础讲解(三)——线性表之循环链表专项练习-CSDN博客
个人主页:樱娆π-CSDN博客
目录
栈的定义和特点
栈 (stack) 是限定仅在表尾进行插入或删除操作的线性表。 因此, 对栈来说, 表尾端有其 特殊含义, 称为栈顶 (top), 相应地, 表头端称为栈底 (bottom)。 不含元素的空表称为空栈。
栈又称为后进先出 (Last In First Out, LIFO) 的线性表。
由图可知,出栈和入栈都是在栈顶进行的!!
栈的类型定义
栈的基本操作除了入栈和出栈外, 还有栈的初始化、 栈空的判定,以及取栈顶元素。
ADT Stack {
数据对象: D={ai I ai含于EElemSet, i=1, 2, …, n,n>=0}
数据关系: R= { < ai-1, ai > I ai-1,ai含于D, i=2, …, n}
约定 an 端为栈顶, a1端为栈底
基本操作:
}
栈的基本操作
基本操作 | 初始条件 | 操作结果 |
InitStack(&S) | / | 构造一个空栈s |
DestroyStack(&S) | 栈S已存在 | 栈S被销毁 |
ClearStack(&S) | 栈S已存在 | 将S清为空栈 |
StackEmpty(S) | 栈S已存在 | 若栈 s 为空栈, 则返回 true, 否则返回 false |
StackLength (S) | 栈S已存在 | 返回s的元素个数, 即栈的长度。 |
GetTop(S) | 栈S已存在且非空 | 返回s的栈顶元素, 不修改栈顶指针 |
Push(&S,e) | 栈S已存在 | 插入元素e为新的栈顶元素 |
Pop(&S,&e) | 栈S已存在且非空 | 删除S的栈顶元素,并用e返回其值 |
StackTraverse(S) | 栈S已存在且非空 | 从栈底到栈顶依次对S的每个数据元素进行访问 |
顺序栈的表示和实现
顺序栈是指利用顺序存储结构实现的栈,即利用一组地址连续的存储单元依次存放自栈底到 栈顶的数据元素,同时附设指针 top指示栈顶元素在顺序栈中的位置。通常习惯的做法是:以top=0表示空栈。
//----- 顺序栈的存储结构- ----
#define MAXSIZE 100 //顺序栈存储空间的初始分配址
typedef struct
{
SElernType *base; //栈底指针
SElernType *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
![https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=%C2%A0%E9%A1%BA%E5%BA%8F%E6%A0%88%E4%B8%AD%E6%95%B0%E6%8D%AE%E5%85%83%E7%B4%A0%E5%92%8C%E6%A0%88%E6%8C%87%E9%92%88%E4%B9%8B%E9%97%B4%E7%9A%84%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB&pos_id=9budAonz](https://i-blog.csdnimg.cn/direct/d344681095b74e9c8bf50061437ec4be.png)
注:base 为栈底指针, 初始化完成后, 栈底指针 base 始终指向栈底的位置, 若 base 的值为NULL, 则表明栈结构不存在。 top 为栈顶指针, 其初值指向栈底。 每当 插入新的栈顶元素时, 指针 top 增1; 删除栈顶元素时, 指针 top 减l。 因此, 栈空 时, top 和 base 的值相等, 都指向栈底;栈非空时, top 始终指向栈顶元素的上一个 位置。
1.顺序栈的初始化
【算法步骤】
- 为顺序栈动态分配一个最大容最为MAXSIZE 的数组空间, 使 base 指向这段空间的基地 址, 即栈底。
- 栈顶指针 top 初始为 base, 表示栈为空。
- stacksize 置为栈的最大容鼠MAXSIZE
【算法实现】
Status InitStack(SqStack &S)
{//构造一个空栈s
S.base=new SElemType[MAXSIZE]; //为顺序栈动态分配一个最大容扯为 MAXSIZE 的数组空间
if (! S. base) exit (OVERFLOW) ; //存储分配失败
S.top=S.base; //top 初始为 base, 空栈
S.stacksize=MAXSIZE; //stacksize 置为栈的最大容量 MAXSIZE
return OK;
}
2.顺序栈的入栈
【算法步骤】
- 判断栈是否满, 若满则返回ERROR
- 将新元素压入栈顶, 栈顶指针加1
【算法实现】
Status Push (SqStack &S, SElemType e)
{//插入元素e为新的栈顶元素
if(S.top-S.base==S.stacksize) return ERROR; //栈满
*S.top++=e; //元素 e 压入栈顶, 栈顶指针加 1
return OK;
}
3.顺序栈的出栈
【算法步骤】
- 判断栈是否空, 若空则返回ERROR
- 栈顶指针减1, 栈顶元素出栈
【算法实现】
Status Pop(SqStack &S,SElemType &e)
(//删除s 的栈顶元素, 用 e 返回其值
if(S.top==S.base) return ERROR; //栈空
e=*--S.top; //栈顶指针减 1, 将栈顶元素赋给e
return OK;
}
4.取栈顶元素
当栈非空时, 此操作返回当前栈顶元素的值, 栈顶指针保待不变
【算法实现】
SElemType GetTop{SqStack S)
{//返回 s 的栈顶元素, 不修改栈顶指针
if{S.top! =S.base) //栈非空
return *{S.top-1); //返回栈顶元素的值,栈顶指针不变
}
链栈的表示和实现
![](https://i-blog.csdnimg.cn/direct/eb13e41611f84825b86df3e59bbfe063.png)
由于栈的主要操作是在栈顶插入和删除, 显然以链表的头部作 为栈顶是最方便的, 而且没必要像单链表那样为了操作方便附加一 个头结点。
1.链栈的初始化
链栈的初始化操作就是构造一个空栈, 因为没必要设头结点, 所以直接将栈顶指针置空即可
【算法实现】
Status InitStack(LinkStack &S)
{//构造一个空栈 s, 栈顶指针置空
S=NULL;
return OK;
}
2.链栈的入栈
【算法步骤】
- 为入栈元素 e 分配空间, 用指针 p 指向
- 将新结点数据域置为e
- 将新结点插入栈顶
- 修改栈顶指针为 p
【算法实现】
Status Push(LinkStack &S, SElemType e)
{//在栈顶插入元素e
p=new StackNode;
p->data=e;
p->next=S;
S=p;
return OK;
}
3.链栈的出栈
【算法步骤】
- 判断栈是否为空 , 若空则返回ERROR
- 将栈顶元素赋给e
- 临时保存栈顶元素的空间, 以备释放
- 修改栈顶指针, 指向新的栈顶元素
- 释放原栈顶元素的空间
【算法实现】
Status Pop(LinkStack &S,SElemType &e)
{//删除 s 的栈顶元素,用 e 返回其值
if(S==NULL) return ERROR;
e=S->data;
p=S;
S=S->next;
delete p;
return OK;
}
4.取栈顶元素
与顺序栈一样, 当栈非空时, 此操作返回当前栈顶元素的值, 栈顶指针S保持不变
【算法实现】
SElemType GetTop(LinkStack S)
{//返回 s 的栈顶元素, 不修改栈顶指针
if(S! =NULL)
return S->data;
}
栈与递归
所谓递归是指,若在一个函数、 过程或者数据结构定义的内部又直接(或间接)出现定义本身 的应用,则称它们是递归的, 或者是递归定义的。在以下三种情况下, 常常使用递归的方法:
- 定义是递归的
- 数据结构是递归的
- 问题的解法是递归的
————由于博主还是大三的在读生,时间有限,每天会不定时更新一些学习经验和一些32的项目,如果喜欢就点点关注吧,大佬们!!!!————