网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
,
a
2
,
.
.
.
.
a
n
)
S=(a1, a2,…an)
S=(a1,a2,…an),则称
a
1
a1
a1为栈底元素,
a
n
an
an为栈顶元素。栈中元素按
a
1
,
a
2
,
.
.
.
a
n
a1,a2,…an
a1,a2,…an的次序进栈,那么出栈的第一个元素应为栈顶元素。
栈的修改是按照后进先出的原则进行的,因此,栈又称为后进先出(last in first out)的线性表(简称LIFO
)结构
🚢共享栈(节省空间)
两个栈共享一个存储空间,意义在于高效利用存储空间
📌第二种说法:两个栈底分别设置在一个空间的两端,栈顶向中间延伸
共享栈的定义
typedef struct Linknode{
ElemType data; //数据域
struct Linknode \*next; //指针域
}LiStack; //栈类型定义
📌共享栈的栈满情况:当两个栈的top在空间中某一位置相遇时
🚢栈的表示和实现(顺序栈)
和线性表类似,栈也有两种存储表示方法——顺序栈和链栈
顺序栈,即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附加指针top表示栈顶元素在顺序栈中的位置。通常当top=-1时,表示此栈为空栈。
👻顺序栈的定义
# define MaxSize 10 //定义栈中元素的最大个数
typedef struct{
ElemType data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
void testStack(){
SqStack S; //声明一个顺序栈(分配空间)
.....
//后续操作
}
由于栈在使用过程中所需要最大空间的大小很难估计,所以,一般来说,在初始化设空栈时不应限定栈的最大容量,常规做法是:先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐步扩大容量
👻初始化操作
构造一个空栈,分配内存空间
# define MaxSize 10 //定义栈中元素的最大个数
typedef struct{
ElemType data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
void InitStack(SqStack &S){
S.top = -1; //初始化栈顶指针
}
void testStack(){
SqStack S; //声明一个顺序栈(分配空间)
InitStack(S);
.....
//后续操作
}
//栈的判空操作
bool StackEmpty(SqStack S){
if(S.top == -1){
return true; //栈空
}
else{
return false; //不为空
}
}
第二种定义
按设定的初始分配量进行第一次存储分配,base可称为是栈底指针,在顺序占中,它始终指向栈底的位置,若base的值为NULL,则表明栈结构不存在,top表示栈顶指针,其初始值指向栈底,即top==base,空栈可以表示为top==base。每当插入新的栈顶元素时,指针top增加1,删除栈顶元素时,指针top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上
#define STACK\_INIT\_SIZE 100; //存储空间初始分配量
#define STACKINCREMENT 10; //存储空间分配增量
typedef struct{
SElemType \*base; //栈底指针
SElemType \*top; //栈顶指针
int stacksize; //当前已分配的空间
}SqStack;
void InitStack(SqStack &S){
//构造一个空栈
S.base = (SElemType \*)malloc(STACK_INIT_SIZE \* sizeof(SElemType));
if(!S.base) exit(OVERFLOW); //存储分配失败
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
}
void testStack(){
SqStack S; //声明一个顺序栈
InitStack(S);
....
//后续操作
}
👻进栈操作
若栈未满,则将x加入使之成为新栈顶
#define MaxSize 10; //定义栈中元素的最大个数
typedef struct{
ElemType data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//新元素入栈
bool Push(SqStack &S, ElemType x){
if(S.top == MaxSize-1){ //表示栈满了
return false;
}
S.top = S.top + 1; //指针先加一
S.data[S.top] = x; //新元素入栈
return true;
}
👻出栈操作
若栈非空,则释放栈顶元素,并返回。
#define MaxSize 10; //定义栈中元素的最大个数
typedef struct{
ElemType data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//出栈操作
bool Pop(SqStack &S, ElemType &x){
if(S.top == -1){ //栈空,报错
return false;
}
x = S.data[S.top]; //栈顶元素先出栈
S.top = S.top - 1; //指针再减1
return true;
}
👻读取栈顶元素
若栈非空,则用x返回栈顶元素
#define MaxSize 10; //定义栈中元素的最大个数
typedef struct{
ElemType data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//读取栈顶元素
bool GetTop(SqStack &S, ElemType &x){
if(S.top == -1){ //栈空,报错
return false;
}
x = S.data[S.top]; //记录栈顶元素
return true;
}
🚢栈的表示和实现(链栈)
对于链栈的基本操作来说,和单链表的插入删除很类似,所以就不在赘述,链栈的入栈和出栈操作,其实就对应单链表的插入和删除操作
👻链栈的定义
typedef struct Linknode{
ElemType data; //数据域
struct Linknode \*next; //指针域
}LiStack; //栈类型定义
栈的非法操作
📌上溢:当栈满了的情况下再次放入元素会造成此情况
📌下溢:当栈空了的情况下再次删除元素会造成此情况
🚀队列(queue)
🚢队列的定义
和栈相反,队列(queue)是一种先进先出(first in first out
)的线性表(缩写为FIFO
)。它只允许在表的一端进行插入,在另一端进行删除元素。这种数据结构概括起来就和我们平时排队是一样的道理,最早进入到的队列的元素最先离开。
在队列中,只允许插入的一端叫做队尾(rear)
,允许删除的一端则称为队头(front)
。假设队列为
q
=
(
a
1
,
a
2
,
.
.
.
a
n
)
,
q=(a1,a2,…an),
q=(a1,a2,…an),那么,
a
1
a1
a1就是队头元素,
a
n
an
an就是队尾元素。队列中的元素是按照
a
1
,
a
2
,
a
3…
a
n
a1,a2,a3…an
a1,a2,a3…an的顺序进入的,退出队列也只能按照这个次序依次退出,也就是说,只有在
a
1
,
a
2
,
a
3…
a
n
−
1
a1,a2,a3…an-1
a1,a2,a3…an−1都离开队列之后,
a
n
an
an才能退出队列
- 📌队首队尾指针的两种指法
- ⭐队首指针(front)指向:队头元素的前一个存储位置
- ⭐队尾指针(rear)指向:队尾元素
- ⚡队首指针(front)指向:队头元素
- ⚡队尾指针(rear)指向:队尾元素的下一个存储位置
📌假溢出:队中有空间,元素无法入队
🚢队列的顺序表示和实现(顺序队列)
和顺序栈类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放队列头到队列尾的元素之外,还需要附设两个指针front
和rear
分别指示队列头元素以及队列尾元素的位置。基本操作基于循环队列,循环队列的引出是为了解决假溢出的问题。
- 📌循环队列的性质
- ⛅数组实现
- 空队列:front == rear
- 满队列:牺牲一个单元判满(不牺牲的话队空队满无法区分)
- (rear+1)% maxSize == front
- 进队:rear新 = (rear旧+1)% maxSize
- 出队:front新 = (front旧+1)% maxSize
- 队中元素个数/长度:(rear - front + maxSize) % maxSize
- ⛅数组实现
👻初始化操作
初始化队列,构造一个空队列
#define MaxSize 10 //定义队列中元素的最大个数
typedef struct{
ElemType data[MaxSize]; //用静态数组存放队列元素
int front, rear; //队头指针和队尾指针
}SqQueue;
//初始化队列
void InitQueue(SqQueue &Q){
//初始化 队头、队尾指针指向0
Q.rear = Q.front = 0;
}
void testQueue(){
//声明一个队列(顺序存储)
SqQueue Q;
InitQueue(Q);
...
//后续操作
}
//判断队列是否为空
bool QueueEmpty(SqQueue Q){
if(Q.rear == Q.front){ //队空条件
return true;
}else{
return false;
}
}
👻入队操作
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
e &Q){
//初始化 队头、队尾指针指向0
Q.rear = Q.front = 0;
}
void testQueue(){
//声明一个队列(顺序存储)
SqQueue Q;
InitQueue(Q);
…
//后续操作
}
//判断队列是否为空
bool QueueEmpty(SqQueue Q){
if(Q.rear == Q.front){ //队空条件
return true;
}else{
return false;
}
}
##### 👻入队操作
[外链图片转存中...(img-byE0nxM7-1715432537753)]
[外链图片转存中...(img-PzFjl2CQ-1715432537753)]
[外链图片转存中...(img-2nLL0W60-1715432537754)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**