一文教你数据结构体栈和队列的实现

news2024/11/19 7:24:26

前言:

        关于c语言的学习已经差不多更新完毕,如果发现个别知识点,我还会继续更新,但目前已经准备往c++和数据结构的重心挪动,这篇文章就是向大家讲述数据结构中栈和队列的实现。 

 💞 💞  欢迎来到小马学习代码博客!!!! 

          你来人间一趟,你要看看太阳!!!!

目录

前言:

一、数据结构体栈 

1.1栈的概念及结构:

1.2栈的实现:

 1.2.1栈的定义:

1.2.2栈的初始化:     

1.2.3栈的销毁:

 1.2.4判断栈是否为空:

1.2.5栈的压栈(push):

1.2.6栈的出栈(Pop):

 1.2.7栈顶的元素查看:    

1.2.7栈的元素个数:     

1.3栈实现的全部代码: 

1.3.1  .c

1.3.2   .h

1.3.3   test

二、数据结构队列:

2.1数列的概念和结构:

2.2队列的实现:

 2.2.1队列的定义: 

2.2.2队列的初始化:   

 2.2.3队列的销毁:   

 2.2.4队列判断是否为空:   

 2.2.5队列插入(push):   

 2.2.6队列出队(Pop):   

2.2.7队头元素:   

2.2.8队尾元素:   

2.2.9队的人员个数: 

2.3队列实现的全部代码: 

2.3.1  .c

2.3.2  .h

2.3.3  test

3、总结:


 

一、数据结构体栈 

1.1栈的概念及结构:

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
 
出栈:栈的删除操作叫做出栈。出数据也在栈顶

 ~~~~记住一个原则,先进的后出,后进的先出。~~~~

1.2栈的实现:

              栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。我们保证首先插入的后面出来就行。

 1.2.1栈的定义:

typedef int STDataType;  //重定义int
typedef struct Stack{
    STDataType* a;            
    STDataType top;        //栈顶
    STDataType capicity;
    
}ST;

1.2.2栈的初始化:     

void StackInit(ST*ps)
{
    assert(ps);
    ps->a=NULL;  //先指向空指针
    ps->top=ps->capicity=0;    初始化都为零
}

1.2.3栈的销毁:

void StackDestroy(ST*ps)
{
    assert(ps);  //断言一下防止空指针
    free(ps);        //进行释放因为我申请的是动态内存
    ps=NULL;        
    ps->top=0;
    ps->capicity=0;
}

 1.2.4判断栈是否为空:

bool StackEmpty(ST*ps)
{
    assert(ps);
    return ps->top==0; //如果top等于0则证明栈为空,返回true
}

1.2.5栈的压栈(push):

void StackPush(ST*ps,STDataType x)
{
    assert(ps); //断言一下
    if(ps->top==ps->capicity)  //如果top(栈顶)=capacity则证明容量已经满了需要扩容一下
    {
        int  newcapicity=ps->capicity==0?4:(ps->capicity)*2;  //和顺序表扩容一样
        STDataType* ptr = (STDataType*)realloc(ps->a, newcapicity*sizeof(STDataType));   //进行动态扩容
        if(ptr==NULL)     //防止扩容失败
        {
            perror("StackPush");
            exit(-1);
        }
        ps->a=ptr;    //把扩容成功的地址传给a
        ps->capicity=newcapicity;    //把扩容后的新newcapicity给capacity
    }
    ps->a[ps->top]=x;   // 插入元素x
    ++ps->top;        //top进行++
}

1.2.6栈的出栈(Pop):

void StackPop(ST*ps)
{
    assert(ps);
    assert(!StackEmpty(ps)); //这里判断是否为空栈如果为空栈就不能在进行出栈了
    --ps->top;  //只需要让top减一个就行了
}

 1.2.7栈顶的元素查看:    

STDataType StackTop(ST* ps)
{
    assert(ps);
    assert(!StackEmpty(ps));
    
    return ps->a[ps->top - 1]; //因为进行push后top++了一下,所以栈顶需要top-1
}

1.2.7栈的元素个数:     

int StackSize(ST* ps)
{
    assert(ps);

    return ps->top;
}

栈还是比较容易实现的,如果熟练掌握顺序表我相信大家还是很容易就能把栈写出来。

1.3栈实现的全部代码: 

1.3.1  .c

#include "Stack.hpp"
void StackInit(ST*ps)
{
    assert(ps);
    ps->a=NULL;
    ps->top=ps->capicity=0;
}
void StackDestroy(ST*ps)
{
    assert(ps);
    free(ps);
    ps=NULL;
    ps->top=0;
    ps->capicity=0;
}
void StackPush(ST*ps,STDataType x)
{
    assert(ps);
    
   
    if(ps->top==ps->capicity)
    {
        int  newcapicity=ps->capicity==0?4:(ps->capicity)*2;
        STDataType* ptr = (STDataType*)realloc(ps->a, newcapicity*sizeof(STDataType));
        if(ptr==NULL)
        {
            perror("StackPush");
            exit(-1);
        }
        ps->a=ptr;
        ps->capicity=newcapicity;
    }
    ps->a[ps->top]=x;
    ++ps->top;
}
bool StackEmpty(ST*ps)
{
    assert(ps);
    return ps->top==0;
}
void StackPop(ST*ps)
{
    assert(ps);
    assert(!StackEmpty(ps));
    --ps->top;
}
STDataType StackTop(ST* ps)
{
    assert(ps);
    assert(!StackEmpty(ps));
    
    return ps->a[ps->top - 1];
}
int StackSize(ST* ps)
{
    assert(ps);

    return ps->top;
}

1.3.2   .h

#ifndef Stack_hpp
#define Stack_hpp

#include <stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
typedef int STDataType;
typedef struct Stack{
    STDataType* a;
    STDataType top;
    STDataType capicity;
    
}ST;
void StackInit(ST*ps);
void StackDestroy(ST*ps);
void StackPush(ST*ps,STDataType x);
void StackPop(ST*ps);
bool StackEmpty(ST*ps);
STDataType StackTop(ST* ps);
int StackSize(ST* ps);

#endif /* Stack_hpp */

1.3.3   test

测试我这里是随便测试了一下,大家可以自己进行不同的测试就行不必和我一样

#include "Stack.hpp"
    void TestStack()
    {
        ST st;
        StackInit(&st);
        StackPush(&st, 1);
        StackPush(&st, 2);
        StackPush(&st, 3);
        printf("%d ", StackTop(&st));
        printf("%d ",StackSize(&st));
        StackPop(&st);
        //printf("%d ", StackTop(&st));
        StackPop(&st);

        StackPush(&st, 4);
        StackPush(&st, 5);

        while (!StackEmpty(&st))
        {
            printf("%d ", StackTop(&st));
            StackPop(&st);
        }
        printf("\n");
    }
    
int main()
{
    TestStack();
    return 0;
}

二、数据结构队列:

2.1数列的概念和结构:

        队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头。  队列和栈的区别就是先进的后出,就和排队买东西一样,先排队的先买,说白了就是先到先得。

2.2队列的实现:

        队列要用到头删,因为第一个进入的要第一个删除,这样用数组就不太合适,因为数组的头删是0(n),时间复杂度比较大,这里我们用链表就是比较合适的选择。

 2.2.1队列的定义: 

typedef int QDataType;
typedef struct QueueNode
{
    struct QueueNode*next;
    QDataType data;
}QNode;
typedef struct Queue
{
    QNode* head;   //队列要有一个头
    QNode* rear;    //队列要有一个尾
    int size;    
}Queue;

2.2.2队列的初始化:   

void QueueInit(Queue*pq)
{
    assert(pq); //断言防止传入空指针
    pq->head=NULL;
    pq->rear=NULL;
    pq->size=0;
}

 2.2.3队列的销毁:   

void QueueDestroy(Queue*pq)
{
    assert(pq);
    QNode *cur=pq->head; //定一个节点进行遍历一个个销毁
    while(cur)
    {
        QNode *del=cur; 
        free(cur);
        cur=del->next;
    }
    pq->head=NULL;
    pq->rear=NULL;
}

 2.2.4队列判断是否为空:   

bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head == NULL && pq->rear == NULL;
}

 2.2.5队列插入(push):   

void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    QNode*newnode=(QNode*)malloc(sizeof(QNode)); //插入前先创建一个节点
    if(newnode==NULL)            //这是判断是否申请成功
    {
        perror("newnode");
        exit(-1);
    }
    else
    {
        newnode->data=x;
        newnode->next=NULL;
    }
    if(pq->rear==NULL)        //两种情况这是尾节点位空的时候
    {
        pq->rear=pq->head=newnode;
    }
    else                //这是尾节点不为空的时候
    {
        pq->rear->next=newnode;
        pq->rear=newnode;
    }
    pq->size++;
}

 2.2.6队列出队(Pop):   

void QueuePop(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));  //判断队列是否为空
    if(pq->head->next==NULL)    //如果只有一个头节点情况
    {
        free(pq->head);
        pq->head=pq->rear=NULL;
    }
    else                //不止只有头节点的情况
{          
    QNode* del;
    del=pq->head;
    pq->head=pq->head->next;
    free(del);
    del=NULL;
    }
    pq->size--;
}

2.2.7队头元素:   

QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    return pq->head->data;
}

2.2.8队尾元素:   

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));
    return pq->rear->data;
}

2.2.9队的人员个数: 

int QueueSize(Queue* pq)
{
    assert(pq);
    return pq->size;
}

2.3队列实现的全部代码: 

2.3.1  .c

#include"Queue.h"
void QueueInit(Queue*pq)
{
    assert(pq);
    pq->head=NULL;
    pq->rear=NULL;
    pq->size=0;
}
void QueueDestroy(Queue*pq)
{
    assert(pq);
    
    QNode *cur=pq->head;
    while(cur)
    {
        QNode *del=cur;
        free(cur);
        cur=del->next;
    }
    pq->head=NULL;
    pq->rear=NULL;
}
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    QNode*newnode=(QNode*)malloc(sizeof(QNode));
    if(newnode==NULL)
    {
        perror("newnode");
        exit(-1);
    }
    else
    {
        newnode->data=x;
        newnode->next=NULL;
    }
    if(pq->rear==NULL)
    {
        pq->rear=pq->head=newnode;
    }
    else
    {
        pq->rear->next=newnode;
        pq->rear=newnode;
    }
    pq->size++;
}
void QueuePop(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));
    if(pq->head->next==NULL)
    {
        free(pq->head);
        pq->head=pq->rear=NULL;
    }
    else{
    QNode* del;
    del=pq->head;
    pq->head=pq->head->next;
    free(del);
    del=NULL;
    }
    pq->size--;
}
bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head == NULL && pq->rear == NULL;
}
QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));
    return pq->rear->data;
}
int QueueSize(Queue* pq)
{
    assert(pq);
    return pq->size;
}

2.3.2  .h


#ifndef Queue_h
#define Queue_h

#include <stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
    struct QueueNode*next;
    QDataType data;
}QNode;
typedef struct Queue
{
    QNode* head;
    QNode* rear;
    int size;
}Queue;
void QueueInit(Queue*pq);
void QueueDestroy(Queue*pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
bool QueueEmpty(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);



#endif /* Queue_h */

2.3.3  test

#include"Queue.h"
void test()
{
    Queue q;
    QueuePush(&q,1);
    QueuePush(&q,2);
    QueuePush(&q,3);
    QueuePush(&q,4);
    QueuePush(&q,5);
    printf("%d \n",QueueSize(&q));
    printf("%d ",QueueFront(&q));
    QueuePop(&q);
    printf("%d ",QueueFront(&q));
    QueuePop(&q);
    printf("%d ",QueueFront(&q));
    printf("%d ",QueueBack(&q));
    
    QueueDestroy(&q);
    
}
int main()
{
    test();
    return 0;
}

3、总结:

        关于栈和队列是数据结构中比较重要的一点,这篇博客我把栈和队列的实现全部写出来了,同时最后有他全部的代码,但我的建议是大家可以尝试一下自己去完成栈和队列的代码实现,在实现过程中也就是我们的学习过程!!!!!!!

 最后小马码文不易,如果觉得有帮助就多多支持哈!!!^ _ ^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/80970.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VoIP通话-基于SIP协议的Asterisk(一)-实现流程

文章首发及后续更新&#xff1a;https://mwhls.top/4122.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; VoIP通话-基于SIP协议的Asterisk该篇仅包含实现流程&#…

实验12 动态查找2022

A. DS二叉排序树之创建和插入 给出一个数据序列&#xff0c;建立二叉排序树&#xff0c;并实现插入功能 对二叉排序树进行中序遍历&#xff0c;可以得到有序的数据序列 输入 第一行输入t&#xff0c;表示有t个数据序列 第二行输入n&#xff0c;表示首个序列包含n个数据 第…

Vue 基础详解 | 系统性学习 | 无知的我费曼笔记

无知的我正在复盘Vue 该笔记特点是 重新整理了涉及资料的一些语言描述、排版而使用了自己的描述对一些地方做了补充说明。比如解释专有名词、类比说明、对比说明、注意事项提升了总结归纳性。尽可能在每个知识点上都使用一句话 || 关键词概括更注重在实际上怎么应用提出并回答…

spring——AOP面向切面编程—— 自动代理——根据 Bean 名称创建代理对象根据切面中信息创建代理对象...

自动代理 在前面的案例中&#xff0c;所有目标对象(Target Bean)的代理对象(Proxy Bean)都是在 XML 配置中通过 ProxyFactoryBean 创建的。 但在实际开发中&#xff0c;一个项目中往往包含非常多的 Bean&#xff0c; 如果每个 Bean 都通过 ProxyFactoryBean 创建&#xff0c;那…

MySQL~InnoDB关键特性(插入缓存、俩次写、自适应哈希索引、异步IO

一般情况下&#xff0c;主键是行唯一的标识符。通常应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。因此&#xff0c;插入聚集索引一般是顺序的&#xff0c;不需要磁盘的随机读取。因为&#xff0c;对于此类情况下的插入&#xff0c;速度还是非常快的。 如果索引…

Selenium4+Python3系列 - 测试框架的设计与开发

框架搭建 整个框架的实现&#xff0c;大约也就1.5天&#xff0c;关于框架的开发并不是很难&#xff0c;主要难在测试报告增加失败自动截图功能和echart的饼子图统计功能&#xff0c;两者的整合花了近半天的时间吧。 效果&#xff1a; 1、核心思想 延续使用Page Object和Page …

RabbitMQ入门(三)消息应答与发布确认

前言&#xff1a; 消息应答与发布确认都是保证消息不丢失。而重复消费问题则是消息幂等性。&#xff08;之后会说幂等性&#xff09; 消息应答&#xff1a; 应答功能属于消费者&#xff0c;消费者在接收到消息并且处理该消息之后&#xff0c;告诉 rabbitmq 它已经处理了&…

深度学习——残差网络(ResNet)笔记

残差网络&#xff1a;经常使用的网络之一 1.随着神经网络的不断加深能改进精度吗&#xff1f; 不一定 ①蓝色五角星表示最优值&#xff0c;Fi闭合区域表示函数&#xff0c;闭合区域的面积代表函数的复杂程度。在这个区域能够找到一个最优的模型&#xff08;区域中的一个点表…

「重学JS」带你一文吃透作用域与闭包

前言 学习了这么久前端&#xff0c;发现自己对于基础知识的掌握并没有那么通透&#xff0c;于是打算重新学一遍JS&#xff0c;借用经济学的一句话&#xff1a;JS基础决定能力高度&#x1f926;&#x1f3fb; 基础很重要&#xff0c;只有基础好才会很少出 bug&#xff0c;大多数…

二叉树的性质

由于二叉树的结构特殊&#xff0c;会有一系列的数学性质 性质一&#xff1a;对于一棵二叉树&#xff0c;第i层的最大结点数量为 个&#xff0c;比如二叉树的第一层只有一个根结点&#xff0c;而二叉树的第三层可以有 个结点。 性质二&#xff1a;对于一棵深度为k的二叉树&am…

【Python】函数

文章目录1. 函数介绍2. 函数的定义与调用3. 函数参数4. 函数返回值5. 变量作用域6. 函数执行过程7. 链式调用8. 嵌套调用9. 函数递归10. 参数默认值11关键字参数1. 函数介绍 编程中的函数不同于数学中的函数&#xff1a; 数学上的函数&#xff0c;比如 y sin x&#xff0c;x…

Vue快速上门|了解MVVM

1.1、先了解下MVVM VUE是基于MVVM思想实现的,❓那什么是MVVM呢?—— MVVM,是Model-View-ViewModel的缩写,是一种软件架构模式。其核心思想就是分离视图、数据、逻辑,VUE框架解决了数据Model到视图View的双向绑定,我们只关注业务逻辑ViewModel即可,极大的提高的编程效率…

BadUSB超详细制作, 实现CobaltStrike远控上线

前言 在2014年美国黑帽大会上&#xff0c;安全研究人员JakobLell和独立安全研究人员Karsten Nohl展示了他们称为“BadUSB”的攻击方法&#xff0c;这种攻击方法让USB安全和几乎所有和USB相关的设备(包括具有USB端口的电脑)都陷入相当危险的状态 现在的USB设备很多&#xff0c…

高级篇之ENC1当作采集卡使用方案推荐

高级篇之ENC1当作采集卡使用0 背景&#xff1a;1 准备工作2 连接示意图3 配置步骤&#xff1a;3.1 在笔记本电脑上安装NDI4工具3.2 ENC1设备连接3.3 配置电脑的USB网卡的IP地址3.4 配置ENC1设备3.5 打开NDI工具的虚拟输入功能0 背景&#xff1a; HDMI视频采集卡分为内嵌式采集…

【GCC编译优化系列】宏定义名称与函数同名是一种什么骚操作?

作者简介 *架构师李肯&#xff08;全网同名&#xff09;**&#xff0c;一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验&#xff0c;深耕IoT领域多年&#xff0c;熟知IoT领域的业务发展&#xff0c;深度掌握IoT领域的相关技术栈&#xff0c;包括但不限于主流…

​全网最牛的Fiddler系列文章(一):fiddler的介绍及安装​

Fiddler(1)&#xff1a;fiddler的介绍及安装 Fiddler简介 Fiddler是比较好用的web代理调试工具之一&#xff0c;它能记录并检查所有客户端与服务端的HTTP/HTTPS请求&#xff0c;能够设置断点&#xff0c;篡改及伪造Request/Response的数据&#xff0c;修改hosts&#xff0c;限…

【UEFI实战】Redfish的BIOS实现1

Redfish的BIOS实现 EDK2提供了Redfish框架&#xff0c;用来实现带外的BIOS配置&#xff0c;其基本框架如下&#xff1a; 通过RedfishPkg中提供的Driver&#xff0c;可以实现BIOS与BMC或者其它的软件进行通信。它主要分为两个部分&#xff0c;分别是Client和Foundation。Client…

[论文解析]DREAMFUSION: TEXT-TO-3D USING 2D DIFFUSION

code links&#xff1a;dreamfusion3d.github.io 文章目录OverviewWhat problem is addressed in the paper?What is the key to the solution?What is the main contribution?What can we learn from ablation studies&#xff1f;Potential fundamental flaws; how this w…

MATLB|基于粒子群算法的能源管理系统EMS(考虑光伏、储能 、柴油机系统)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清…

原子操作类之18罗汉增强

原子操作类之18罗汉增强 是什么 都是java.util.concurrent.atomic包下的 有红框圈起来的&#xff0c;也有蓝框圈起来的&#xff0c;为什么&#xff1f; 阿里巴巴Java开发手册 为什么说18罗汉增强&#xff0c;却只有16个 再分类 基本类型原子类 AtomicInteger AtomicBoolea…