(详解)数据结构-----------栈与队列 c语言实现

本章将会详细讲解以下知识点:

目录

一:栈

        1:栈的定义,栈的特点

        2:用什么结构来实现栈与原因的分析?

        3:  (超详解)栈的常用接口并且附上测试用例

二:队列

        1:队列的定义,队列的特点

        2:用什么结构来实现队列与原因的分析?

        3:(超详解)队列的接口并且附上测试用例


正文开始~:-^-

        1:栈的定义及其特点

        首先栈是一种特殊线性表,其只能在一端进行插入删除的操作,进行数据删除插入的一端我们称它为栈顶,另外一端为栈底。栈中的数据元素遵循后进先出的原则。

        下面是栈的操作的叫法:

                压栈:表示数据元素插入到栈中,又称为进栈/入栈。入数据在栈顶

                出栈:表示栈中数据元素的删除的操作。出数据在栈顶

                栈的特点只能在栈一端进行数据元素的插入与删除,数据元素遵循后进先出的原则。

        2:用什么结构来实现栈与原因?

        经过前面我们对比顺序表与链表的优缺点,在实现栈的时候我们首选使用顺序表来进行实现栈这种数据结构。当然也可以使用链表来实现。

        原因:我们根据栈具有先进后出的特点,它只能在栈顶进行数据元素的插入与删除。

        而我们的顺序表就非常适合它,顺序表的尾插与尾删的时间复杂度都是O(1),且顺序表的缓存利用率比链表快,所以顺序表的结构更加优于链表。

         3:(详解)栈的常用接口

        栈的常用操作有:栈的初始化,栈的销毁,栈的入栈,栈的出栈,获取栈顶元素的值

        栈是否为空的判读,栈的大小

        在讲解这些接口之前,我们先来讲解栈的定义

        包含三个成员变量,S是我们开辟空间的首地址,top是用来记录元素有多少个,同时是数组中元素最后一个元素的下一个位置,capacity是用来表示数组空间容量的大小。

        代码如下:

//动态的顺序栈
typedef int STDataType;

typedef struct Stack
{
	STDataType* S;
	int top;//用来表示栈中最后一个元素的下一个元素的位置
	int capacity;
}ST;

        1:栈的初始化:将三个成员变量的值全部弄为空或者是0

        代码如下:

void InitStack(ST* ps)
{
	assert(ps);
	ps->capacity = 0;
	ps->top = 0;
	ps->S = NULL;
}

        2:栈的入栈操作:每次入栈之前我们先要判断空间是否足够,然后在直接使用顺序表随机访问的特点对栈进行尾插,每次入栈完成我们都需要将top++。

        在下面代码中有一个非常精髓的地方,由于我们初始化的时候并没有给数组开辟空间之类的,所以我们巧用了三目运算符来对我们新开辟的空间的大小进行分配,如果是第一次我们就将空间的大小搞成4,之后的过程就是一次扩2倍的空间。

         代码如下:

        

void PushStack(ST* ps, STDataType x)
{
	assert(ps);
	//先检查空间够不够
	if (ps->top == ps->capacity)
	{
		int newcapcity = (ps->capacity == 0 ? 4 : 2 * ps->capacity);
		STDataType* tmp = (STDataType*)realloc(ps->S, sizeof(STDataType) * newcapcity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->S = tmp;
		ps->capacity = newcapcity;
	}
	ps->S[ps->top] = x;
	++ps->top;
}

         3:栈的出栈操作:这里我们需要用暴力的解法先判断栈是否为空,如果为空就给我们报错,不为空才能进行出栈的操作,然后我们的就top--。

        代码如下:

void PopStack(ST* ps)
{
	assert(ps);
	//非空
	assert(ps->top > 0);

	ps->top--;

}

        4:栈的获取栈顶元素的操作:首先还是得判断栈是否为空,为空就这个接口就会报错。

        在这个代码中我们要注意的是我们栈顶元素得下标并不是top而是top-1

        代码如下:

        

STDataType GetStack(ST*ps)
{
	assert(ps);
	//非空
	assert(ps->top > 0);

	return ps->S[ps->top-1];
}

        5:栈的大小:我们直接返回top就行。

        代码如下:

        

int SizeStack(ST* ps)
{
	assert(ps);
	
	return ps->top;
}

        6:判断栈是否为空:这里如果top为0,则说明栈中无元素返回true,如果有元素返回true,这里要注意c语言中并没有这两个关键字,我们需要引入头文件<stdbool.h>

        代码如下:

        

bool EmptyStack(ST* ps)
{
	assert(ps);
	  //这里代码的意思是如果top为0,则返回真,不为0返回false
    return ps->top == 0;
  
}

        为了体现栈的特点所以我们在打印出栈中数据的时候,并不是直接遍历数组的

        我们使用的是--->

        

while (!EmptyStack(&st))
	{
		printf("%d ", GetStack(&st));
		PopStack(&st);
	}

        这里是每次取栈顶的元素,然后在删除栈顶的元素。这样才能体现出栈的特点。

        

        图解:

         

        栈的详解就到这里结束了。



    1:队列的定义与特点

        队列的定义:队列也是一种特殊的线性表,它只能在一端进行插入操作,在另外一端进行删除的操作,我们将插入一端称为队尾,将删除的一端我们称之为队头,这种结构在我们生活中非常常见,我们可以想象一下我们在食堂排队的情况,如果有人来了那么它就会往队尾进行插入,打完饭的人则会从队头出队。

        出队:将队头的元素进行删除的操作

        入队:在队尾插入数据的操作。

        队列特点:只能在队头进行删除的操作,在队尾进行插入的操作,遵循先进先出原则

        图:

        

         2:用啥结构来实现队列与原因?

        先公布答案:相对与顺序表来说我们一般使用链表来实现队列这一数据结构。

        原因:链表在进行头删的时候更加方便,在进行尾插的时候我们只需要定义一个尾指针就可以节省时间了。

        3:(详解)队列的常用接口

        队列的接口包括:初始化队列,销毁队列,入队操作,出队操作,判断队列是否为空

获取队头元素,获取队尾元素,判断队列的大小。 

       首先我们先来了解队列的结构代码分析:

typedef int QueueDataType;

typedef struct QNode
{
	struct QNode* next;
	QueueDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;//用来记录有多少个结点,可以直接算大小
}Que;

     首先队列的每个元素都是一个链表的基本结构,我们只需要记录链表的头节点与尾结点我们就可以将队列给表示出来,而又因为我们一般传参的时候只传地址所以我们就将头指针与尾指针定义到一个结构体当中,并且增加一个成员变量size,用来记录队列元素的个数。

            将两个指针放到同一个结构体中,有一个好处就是我们只需要通过结构体指针就可以改变我们的指针的值,不然就需要使用二级指针来修改它们的值。

 

        1:队列的初始化:如果你和我的初始化不同那么可能会导致后面一些接口中步骤有些差异。初始化并不唯一

        代码如下:

            

void QueueInit(Que* pq)
{
	assert(pq);
	pq->head = pq->tail = 0;
	pq->size = 0;
}

        2:入队操作:这里需要分为两种情况,第一张是插入第一个元素的时候我们需要将两个指针的指向给改变,另外一种情况我们只需要在尾指针的后面插入一个新的结点即可,与此同时我们将尾指针指向新结点,插入之后我们的size++;

        代码如下:

        

void QueuePush(Que* pq, QueueDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail:");
		exit(-1);
	}
	
	//为第一个结点的时候
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	//不是第一个结点
	else
	{
		pq->tail->next = newnode;
	}
	pq->tail = newnode;
	newnode->data = x;
	newnode->next = NULL;
	pq->size++;
}

        3:出队操作:首先得判断队列中是否含有数据元素,且有两类,一类是队列中只有一个元素,那么我们需要将这个元素删除,并且将head与tail的值置为空,在size--;

        代码如下:

void QueuePop(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	//只有一个结点的时候
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* phead = pq->head->next;
		free(pq->head);
		pq->head = phead;
	}
	pq->size--;

       4:获取队头元素:这个非常简单,先判断队列是否为空,不为空我们只需要返回head->data,就行。

        代码如下:

QueueDataType QueueFront(Que* pq)
{
	assert(pq);//判断pq是否有意义
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

        5:获取队尾元素:与上面的思路类似,只需要返回tail指针所指向的数据元素就行

        

QueueDataType QueueBack(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

        6:判断队列是否为空:为空那么head指针就为空,head为NULL则返回true,否则返回false

        代码如下:

               

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

        7:队列的元素个数判断:我们根据我们所定义的结构可在,我们只需要返回size即可。

        

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

        在某种情况下可以使用栈转化为队列,也可以使用队列转化为栈,让我们一起想一想它是如何转化的吧。


 

 !!!本章完,感谢大家的耐心观看!

        

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ArcGIS微课1000例】0073:ArcGIS探索性回归分析案例

一、探索性回归工具简介 “探索性回归”工具会对输入的候选解释变量的所有可能组合进行评估,以便根据用户所指定的指标来查找能够最好地对因变量做出解释的 OLS 模型。 给定一组候选解释变量,找出正确指定的 OLS 模型: 用法: 工具还会生成一个可选表,该表包括所有满足…

Mybatis1.4 多条件查询

1.4 多条件查询 1.4.1 编写接口方法1.4.2 编写SQL语句1.4.3 编写测试方法1.4.4 动态SQL 我们经常会遇到如上图所示的多条件查询&#xff0c;将多条件查询的结果展示在下方的数据列表中。而我们做这个功能需要分析最终的SQL语句应该是什么样&#xff0c;思考两个问题 条件表达式…

SpringBoot整合JUnit、MyBatis、SSM

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 SpringBoot整合 一、SpringBoot整合JUnit二、Spri…

无人机甚高频无线电中继通讯U-ATC118

简介 甚高频无线电中继通讯系统使用经过适航认证的机载电台连接数字网络传输模块&#xff0c;通过网络远程控制无缝实现无人机操作员与塔台直接语音通话。无人机操作员可以从地面控制站远程操作机载电台进行频率切换、静噪开关、PTT按钮&#xff0c;电台虚拟面板与真实面板布局…

小程序数据导出文件

小程序josn数据生成excel文件 先从下载传送门将xlsx.mini.min.js拷贝下来&#xff0c;新建xlsx.js文件放入小程序项目文件夹下。 const XLSX require(./xlsx)//在需要用的页面中引入// 定义导出 Excel 报表的方法exportData() {const that thislet newData [{time:2021,val…

【Seata】00 - Seata Server 部署(Windows、Docker 基于 Jpom)

文章目录 前言参考目录版本说明Windows 部署 seata-server1&#xff1a;下载压缩包2&#xff1a;文件存储模式3&#xff1a;db 存储模式3.1&#xff1a;建表3.2&#xff1a;修改配置文件3.3&#xff1a;启动脚本4&#xff1a;源码部署 Docker 部署 seata-server &#xff08;基…

程序员必须掌握哪些算法?

一个程序员一生中可能会邂逅各种各样的算法&#xff0c;但总有那么几种&#xff0c;是作为一个程序员一定会遇见且大概率需要掌握的算法。今天就来聊聊这些十分重要的“必抓&#xff01;”算法吧~ 文章目录 一、程序员必须掌握哪些算法&#xff1f;二&#xff1a;常见算法介绍…

flutter高德地图大头针

1、效果图 2、pub get #地图定位 amap_flutter_map: ^3.0.0 amap_flutter_location: ^3.0.0 3、上代码 import dart:async; import dart:io;import package:amap_flutter_location/amap_flutter_location.dart; import package:amap_flutter_location/amap_location_option…

R语言APRIORI关联规则、K-MEANS均值聚类分析中药专利复方治疗用药规律网络可视化...

全文链接&#xff1a;http://tecdat.cn/?p30605 应用关联规则、聚类方法等数据挖掘技术分析治疗的中药专利复方组方配伍规律&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 方法检索治疗中药专利复方&#xff0c;排除外用中药及中西药物合用的复方。最近我们…

每天 26,315 美元罚款?交通安全局要求特斯拉提供 Autopilot数据

根据美国国家公路交通安全管理局&#xff08;NHTSA&#xff09;最近的特别命令&#xff0c;特斯拉公司被要求提供关于其自动驾驶功能Autopilot的相关信息。这一命令是继NHTSA于2021年8月启动初步评估后&#xff0c;在2022年6月升级为正式调查的一部分&#xff0c;NHTSA近期对特…

网络安全法+网络安全等级保护

网络安全法 2014年2月&#xff0c;中央网络安全和信息化领导小组成立&#xff0c;习主席当组长 2017年6月1日&#xff0c;网络安全法正式成立 网络安全是国家安全的重要组成部分没有网络安全就没有国家安全&#xff0c;没有信息化就没有现代化 网络安全法21条 网络安全法31条 …

angular抛出 ExpressionChangedAfterItHasBeenCheckedError错误分析

当变更检测完成后又更改了表达式值时&#xff0c;Angular 就会抛出 ExpressionChangedAfterItHasBeenCheckedError 错误。Angular 只会在开发模式下抛出此错误。 在开发模式下&#xff0c;Angular 在每次变更检测运行后都会执行一次附加检查&#xff0c;以确保绑定没有更改。这…

Nginx到底是什么,他能干什么?

目录 Ngnix是什么&#xff0c;它是用来做什么的呢&#xff1f; 一。Nginx简介 二&#xff0c;为什么要用Nginx呢&#xff1f; 二。Nginx应用 1.HTTP代理和反向代理 2.负载均衡 Ngnix是什么&#xff0c;它是用来做什么的呢&#xff1f; 一。Nginx简介 Nginx是enginex的简写&…

Redis——如何解决redis穿透、雪崩、击穿问题

目录 一、查询商品信息的常规代码示例二、缓存击穿2.1、缓存击穿的理解2.2、缓存击穿的解决方案2.3、解决缓存击穿的代码示例 三、缓存雪崩3.1、缓存雪崩的理解3.2、缓存雪崩的解决方案3.2.1、缓存集中过期的情况3.2.2、缓存服务器宕机的情况3.2.3、缓存服务器断电的情况 3.3、…

springBoot打印精美logo

文章目录 &#x1f412;个人主页&#x1f3c5;JavaEE系列专栏&#x1f4d6;前言&#xff1a;&#x1f380;文本logo &#x1f412;个人主页 &#x1f3c5;JavaEE系列专栏 &#x1f4d6;前言&#xff1a; 本篇博客主要以提供springBoot打印精美logo &#x1f380;文本logo ??…

IDEA遇到 git pull 冲突的几种解决方法

1 忽略本地修改&#xff0c;强制拉取远程到本地 主要是项目中的文档目录&#xff0c;看的时候可能多了些标注&#xff0c;现在远程文档更新&#xff0c;本地的版本已无用&#xff0c;可以强拉 git fetch --all git reset --hard origin/dev git pull关于commit和pull的先后顺…

Web服务器-Tomcat详细原理与实现

Tomcat 安装与使用 &#xff1a;MAC 安装配置使用Tomcat - 掘金 安装后本计算机就相当于一台服务器了&#xff01;&#xff01;&#xff01; 方式一&#xff1a;使用本地安装的Tomcat 1、将项目文件移动到Tomcat的webapps目录下。 2、启动Tomcat 3、在浏览器输入想要加载的…

小程序运营方式有哪些?如何构建小程序运营框架?

​如今&#xff0c;每个企业基本都做过至少一个小程序&#xff0c;但由于小程序本身不具备流量、也很少有自然流量&#xff0c;因此并不是每个企业都懂如何运营小程序。想了解小程序运营方式方法有哪些&#xff1f; 在正式运营小程序前&#xff0c;了解小程序的功能与企业实际经…

天润融通「微藤大语言模型平台2.0」以知识驱动企业高速增长

8月23日&#xff0c;天润融通&#xff08;又称“天润云”,2167.HK&#xff09;&#xff0c;正式发布「微藤大语言模型平台2.0」。 “大模型企业知识企业知识工程”。 “不能有效记录和管理知识的企业是不能持续进步的。在企业的生产流程中&#xff0c;相比于其他场景&#xff0…

Git小白入门——了解分布式版本管理和安装

Git是什么&#xff1f; Git是目前世界上最先进的分布式版本控制系统&#xff08;没有之一&#xff09; 什么是版本控制系统&#xff1f; 程序员开发过程中&#xff0c;对于每次开发对各种文件的修改、增加、删除&#xff0c;达到预期阶段的一个快照就叫做一个版本。 如果有一…