大数据最全数据结构与算法——栈和队列,一文搞懂

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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)指向:队尾元素的下一个存储位置

📌假溢出:队中有空间,元素无法入队

🚢队列的顺序表示和实现(顺序队列)

和顺序栈类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放队列头到队列尾的元素之外,还需要附设两个指针frontrear分别指示队列头元素以及队列尾元素的位置。基本操作基于循环队列,循环队列的引出是为了解决假溢出的问题。

  • 📌循环队列的性质
    • ⛅数组实现
      • 空队列: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;
    }
}

👻入队操作

若队列未满,将x加入,使之称为新的队尾

#define MaxSize 10 //定义队列中元素的最大个数
typedef struct{
    ElemType data[MaxSize];     //用静态数组存放队列元素
    int front, rear;            //队头指针和队尾指针
}SqQueue;

//入队
bool EnQueue(SqQueue &Q, ElemType x){
    if((Q.rear+1)%MaxSize == Q.front){       //判断队列是否已满
        return false;       //对满则报错
    }
    Q.data[Q.rear] = x;     //将x插入队尾
    Q.rear = (Q.rear + 1) % MaxSize;    //队尾指针后移
    return true;
}

👻出队操作

若队列非空,删除队头元素并返回x

#define MaxSize 10 //定义队列中元素的最大个数
typedef struct{
    ElemType data[MaxSize];     //用静态数组存放队列元素
    int front, rear;            //队头指针和队尾指针
}SqQueue;

//出队(删除一个队头元素,并返回x)
bool DeQueue(SqQueue &Q, ElemType &x){
    if(Q.rear == Q.front){      //判断队空
        return false;           //队空则报错
    }
    x = Q.data[Q.front];
    Q.front = (Q.front+1)%MaxSize;
    return true;
}

👻获取队头元素操作

读队头元素,若队列非空,则将队头元素赋值给x

#define MaxSize 10 //定义队列中元素的最大个数
typedef struct{
    ElemType data[MaxSize];     //用静态数组存放队列元素
    int front, rear;            //队头指针和队尾指针
}SqQueue;

//获得队头元素的值,用x返回
bool GetHead(SqQueue Q, ElemType &x){
    if(Q.rear == Q.front){
        return false;       //队空报错
    }
    x = Q.data[Q.front];
    return true;
}


🚢队列的链式表示和实现(链队列)

和线性表类似,队列也可以有两种存储表示

用链表表示的队列简称为链队列,一个链队列显然需要两个分别指示队头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。

链队列的操作即为单链表的插入和删除操作的特殊情况,只是需要修改尾指针或头指针

一般情况下,删除队列头元素时仅需修改头结点中的指针,但当队列中最后一个元素被删除后,队列表尾指针也丢失了,因此需对队尾指针重新赋值(指向头结点)

👻初始化操作

初始化队列,构造一个空队列

📌带头结点:

typedef struct LinkNode{        //链式队列结点
    ElemType data;
    struct LinkNode \*next;
}LinkNode;

typedef struct{     //链式队列
    LinkNode \*front, \*rear  //队列的队头和队尾指针
}LinkQueue;

//初始化队列(带头结点)
void InitQueue(LinkQueue &Q){
    //初始化 front、rear都指向头结点
    Q.front = Q.rear = (LinkNode\*)malloc(sizeof(LinkNode));
    Q.front -> next = NULL;
}

viod testLinkQueue(){


![img](https://img-blog.csdnimg.cn/img_convert/d9cfbc3974e5da5f6d1ee297ea8eacce.png)
![img](https://img-blog.csdnimg.cn/img_convert/9847639b562dee26b12472f006689300.png)
![img](https://img-blog.csdnimg.cn/img_convert/76616ca99fe8068613ff46db6d4ec992.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

       //链式队列结点
    ElemType data;
    struct LinkNode \*next;
}LinkNode;

typedef struct{     //链式队列
    LinkNode \*front, \*rear  //队列的队头和队尾指针
}LinkQueue;

//初始化队列(带头结点)
void InitQueue(LinkQueue &Q){
    //初始化 front、rear都指向头结点
    Q.front = Q.rear = (LinkNode\*)malloc(sizeof(LinkNode));
    Q.front -> next = NULL;
}

viod testLinkQueue(){


[外链图片转存中...(img-jR8ONiyq-1715761784133)]
[外链图片转存中...(img-qTuAiefb-1715761784133)]
[外链图片转存中...(img-xHAsneNl-1715761784133)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值