【数据结构】详细介绍栈和队列,解析栈和队列每一处细节

news2024/11/17 17:53:00

目录

一. 栈

1. 栈的概念

2. 栈的实现

2.1 栈的结构

2.2 初始化栈

2.3 入栈

2.4 出栈

2.5 获取栈顶元素

2.6 获取栈中有效个数

2.7 判断栈是否为空

2.8 销毁栈 

二. 队列

1. 队列的概念

2. 队列的实现 

2.1 队列的结构

2.2 队列初始化 

2.3 销毁队列 

2.4 入队列(队尾) 

2.5 出队列(队头) 

2.6 获取队头数据 

2.7 获取队尾数据 

2.8 获取队列节点个数 

2.9 判断队列是否为空 

3. 循环队列

4. 编程题 设计循环队列 

三. 概念题


一. 栈

1. 栈的概念

1. 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。

2. 进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。

3. 栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

4. 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

5. 出栈:栈的删除操作叫做出栈。出数据也在栈顶。

2. 栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些,因为数组在尾上插入数据的代价比较小。

2.1 栈的结构

1. top表示栈顶数据的下一个位置。

typedef int StackDataType;
typedef struct Stack
{
	StackDataType* arr; //用数组作为存放栈数据的结构
	int top;			//栈顶数据的下一个位置
	int capacity;		//容量
}Stack;

2.2 初始化栈

1. 将结构数据初始化。

void StackInit(Stack* ps)
{
	assert(ps);

	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

2.3 入栈

1. 判断扩容。

2. 数据插入栈顶。

void StackPush(Stack* ps, StackDataType data)
{
	assert(ps);

	//判断扩容
	if (ps->top == ps->capacity)
	{
		int size = ps->capacity == 0 ? 4 : ps->capacity * 2;
		StackDataType* tmp = (StackDataType*)realloc(ps->arr, sizeof(StackDataType)*size);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		ps->arr = tmp;
		ps->capacity = size;
	}

	//入栈
	ps->arr[ps->top++] = data;
}

2.4 出栈

1. 栈不为空才能出栈。

void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}

2.5 获取栈顶元素

1. 判断空栈

StackDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

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

2.6 获取栈中有效个数

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

	return ps->top;
}

2.7 判断栈是否为空

1. 栈空返回真。

bool StackEmpty(Stack* ps)
{
	assert(ps);

	return !ps->top;
}

2.8 销毁栈 

1. 释放空间,初始数据。

void StackDestroy(Stack* ps)
{
	assert(ps);

	free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

 完整代码:Stack/Stack · 林宇恒/DataStructure - 码云 - 开源中国 (gitee.com)


二. 队列

1. 队列的概念

1. 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。

2. 队列具有先进先出FIFO(First In First Out)的特点。

3. 入队列:进行插入操作,这一端称为队尾。

4. 出队列:进行删除操作,这一端称为队头。

2. 队列的实现 

队列也可以使用数组或链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

2.1 队列的结构

1. 需要两个结构体,一个表示节点,一个表示队列整体。

2. 节点的结构包含存放的数据和指向下一个节点的指针。

3. 表示队列的结构包含队头指针和队尾指针还有节点的数量。

typedef int QueueDataType;
typedef struct QueueNode
{
	QueueDataType data;     //数据
	struct QueueNode* next; //下一个节点地址
}QueueNode;

typedef struct Queue
{
	QueueNode* prev; //队头指针
	QueueNode* tail; //队尾指针
	size_t size;     //节点个数
}Queue;

2.2 队列初始化 

1. 传入的队列指针不能为空。

2. 将队列结构体中队头队尾指针置空,节点数量置0。

void QueueInit(Queue* q)
{
	assert(q);

	q->prev = q->tail = NULL;
	q->size = 0;
}

2.3 销毁队列 

1. 传入的队列指针不能为空。

2. 从队头指针开始遍历释放节点直到空停下,并将队头队尾指针置空,节点数量置0。

void QueueDestroy(Queue* q)
{
	assert(q);

	while (q->prev)
	{
		QueueNode* next = q->prev->next;
		free(q->prev);
		q->prev = next;
	}

	q->tail = NULL;
	q->size = 0;
}

2.4 入队列(队尾) 

1. 传入的队列指针不能为空。

2. 创建要入队列的节点

3. 当队列为空时,将队头队尾指针都指向新节点,节点数量加一。

4. 当队列不为空时,将新节点和最后一个节点连接,然后队尾指针指向新节点,节点数量加一。

void QueuePush(Queue* q, QueueDataType data)
{
	//1. 传入的队列指针不能为空。
	assert(q);

	//2. 创建要入队列的节点
	QueueNode* new = (QueueNode*)malloc(sizeof(QueueNode));
	if (new == NULL)
	{
		perror("malloc");
		return;
	}
	new->data = data;
	new->next = NULL;

	//3. 当队列为空时,然后将队头队尾指针都指向新节点,节点数量加一。
	if (q->size == 0)
	{
		q->prev = q->tail = new;
		q->size++;
	}
	//4. 当队列不为空时,将新节点和最后一个节点连接,然后队尾指针指向新节点,节点数量加一。
	else
	{
		q->tail->next = new;
		q->tail = new;
		q->size++;
	}
}

2.5 出队列(队头) 

1. 传入的队列指针不能为空。

2. 队列不能为空。

3. 释放第一个节点,队头指针指向第二个节点,节点数量减一。

4. 当队列删完之后没有节点了,这种情况需要特殊处理,防止队尾指针变成野指针。

void QueuePop(Queue* q)
{
	//1. 传入的队列指针不能为空。
	assert(q);
	//2. 队列不能为空。
	assert(q->size);

	//3. 释放第一个节点,队头指针指向第二个节点,节点数量减一。
	QueueNode* next = q->prev->next;
	free(q->prev);
	q->prev = next;
	q->size--;
	//4. 当队列删完之后没有节点了,这种情况需要特殊处理,防止队尾指针变成野指针。
	if (q->size == 0) q->tail = NULL;
}

2.6 获取队头数据 

1. 队列指针不能为空。

2. 队列不能为空。

3. 返回队头节点存放的数据。

QueueDataType QueueFront(Queue* q)
{
	//1. 队列指针不能为空。
	assert(q);
	//2. 队列不能为空。
	assert(q->size);

	//3. 返回队头节点存放的数据。
	return q->prev->data;
}

2.7 获取队尾数据 

1. 队列指针不能为空。

2. 队列不能为空。

3. 返回队尾节点存放的数据。

QueueDataType QueueBack(Queue* q)
{
	//1. 队列指针不能为空。
	assert(q);
	//2. 队列不能为空。
	assert(q->size);

	//3. 返回队尾节点存放的数据。
	return q->tail->data;
}

2.8 获取队列节点个数 

1. 队列指针不能为空。

2. 返回节点个数。

int QueueSize(Queue* q)
{
	//1. 队列指针不能为空。
	assert(q);

	//2. 返回节点个数。
	return q->size;
}

2.9 判断队列是否为空 

1. 队列指针不能为空。

2. 根据节点数量判断。空返回真。

bool QueueEmpty(Queue* q)
{
	//1. 队列指针不能为空。
	assert(q);

	//2. 根据节点数量判断。空返回真。
	return !q->size;
}

完整代码: Queue/Queue · 林宇恒/DataStructure - 码云 - 开源中国 (gitee.com)

3. 循环队列

1. rear的位置插入数据,然后rear++。

2. pop一次就是front往前移一位。

3. front == rear 表示空。

4. rear+1 == front 表示满,记得取模。

5. 这里使用数组实现,因为单链表不方便获取队尾数据。

4. 编程题 设计循环队列 

链接:. - 力扣(LeetCode)

typedef struct 
{
    int* arr;  //指向队列
    int front; //队头下标
    int rear;  //队尾下标
    int k;     
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->arr = (int*)malloc(sizeof(int)*(k+1));
    obj->front = obj->rear = 0;
    obj->k = k;

    return obj;    
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    //队头下标等于队尾下标时为空。
    return obj->front == obj->rear;    
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    //队尾下标加一等于队头下标时为满,超出数组范围需要取模。
    return (obj->rear+1) % (obj->k+1) == obj->front;    
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    //满了不能插入。
    if(myCircularQueueIsFull(obj)) return false;
    else
    {
        //在队尾放数据,然后队尾加一,记得取模。
        obj->arr[obj->rear] = value;
        obj->rear = (obj->rear+1) % (obj->k+1);
        return true;
    }
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    //空的不能删。
    if(myCircularQueueIsEmpty(obj)) return false;
    else
    {
        //删除数据队头下标直接加一即可,记得取模。
        obj->front = (obj->front+1) % (obj->k+1);
        return true;
    }    
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj)) return -1;
    return obj->arr[obj->front];    
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj)) return -1;
    //当rear等于0时需要特殊处理
    return obj->arr[(obj->rear-1+obj->k+1)%(obj->k+1)];  
}

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->arr);   
    free(obj);
}

三. 概念题

一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。

A 12345ABCDE

B EDCBA54321

C ABCDE12345

D 54321EDCBA

答:B

若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()

A 1,4,3,2

B 2,3,4,1

C 3,1,4,2

D 3,4,2,1

答:C

循环队列的存储空间为 Q(1:100) ,初始状态为 front=rear=100 。经过一系列正常的入队与退队操作后, front=rear=99 ,则循环队列中的元素个数为( )

A 1

B 2

C 99

D 0或者100

答:D

以下( )不是队列的基本运算?

A 从队尾插入一个新元素

B 从队列中删除第i个元素

C 判断一个队列是否为空

D 读取队头元素的值 

答:B

现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设队头不存放数据)

A (rear - front + N) % N + 1

B (rear - front + N) % N

C (rear - front) % (N + 1)

D (rear - front + N) % (N - 1) 

答:B

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

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

相关文章

聊聊适配器模式

目录 适配器模式概念 主要实现方式 主要组成 UML用例图 代码示例 生活场景 应用场景 适配器模式概念 适配器模式属于结构型设计模式,它的主要目的是将一个类的接口转换成客户端所期望的另一种接口形式,使得原本接口不兼容的类可以一起工作。 主…

【New SQL】 -- CockroachDB license change

1、CockroachDB 发布了修改开源协议的 releases 北京时间 2024-08-16 ,CockroachDB 发布了修改开源协议的 releases。 原文链接:Licensing FAQs Evolving our self-hosted offering and license model CockroachDB License change (again) | Product T…

Kali Linux 定制化魔改 添加常见60渗透工具

项目地址:https://github.com/CuriousLearnerDev/kali-linux-kde-beautify 系统版本:kali linux 2024.1 固件类型:BIOS 用户: zss 密码: ss 完整版 系统压缩大小:18.8 GB 解出来:36.00GB 左右 系统版 系统压缩大小&…

《Cloud Native Data Center Networking》(云原生数据中心网络设计)读书笔记 -- 04路由协议的选择

本章要回答的问题: 路由是如何工作的?有哪些类型的路由协议?Clos 拓扑中的路由协议是如何工作的?什么是无编号接口,以及为什么无编号接口如此重要?如何确定最适合自己需求的路由协议? 路由概述 用最简单的话来说,路由是使用数据包的目…

DESeq2差异基因分析和批次效应移除

差异基因鉴定 基因表达标准化 不同样品的测序量会有差异,最简单的标准化方式是计算counts per million (CPM),即原始reads count除以总reads数乘以1,000,000。 这种计算方式的缺点是容易受到极高表达且在不同样品中存在差异表达的基因的影响&#xff…

FunClip,音视频识别,自动化剪辑,文本校对,智能纠错,导出SRT

今天给大家介绍一个自动化剪辑项目——FunClip,该项目是由阿里开源的,可以识别音频、视频中的文字,一键剪辑和添加字幕。 FunClip是一款高效的自动化视频剪辑工具,它利用语音识别技术对视频内容进行分析。用户可以在识别结果中选择所需的文本…

重生奇迹MU 梦幻骑士 真正生而高贵的职业

作为重生奇迹MU梦幻骑士中真正生而高贵的职业,圣骑士是玩家们最为追捧的职业之一。在游戏内,圣骑士拥有着强大的防御和治疗能力,成为团队中不可或缺的存在。如果你正准备选择一个强大的职业,那么不妨考虑成为一名圣骑士&#xff0…

选择文件摆渡系统要遵守的“三要”和“三不要”原则

文件摆渡系统不仅可以实现企业网络隔离后的数据摆渡需求,同时也可以视作企业数据安全及网络安全建设的重要组成部分。文件摆渡系统的选择也很关键,在企业进行筛选时,应该遵守“三要”和“三不要”原则。 “三要”之一:要安全 文件…

MySQL对事务的支持

5.MySQL对事务的支持情况: 5.1. 查看存储引擎对事务的支持情况 : 1.SHOW ENGINES 命令来查看当前 MySQL 支持的存储引擎都有哪些,以及这些存储引擎是否支持事务2.下图可以能看出在 MySQL 中,只有InnoDB类型的存储引擎是支持事务…

轻松搞定 Java7 新特性,示例丰富

Java 7 是 Java 语言的一个主要版本,于 2011 年 7 月 28 日正式发布。 由 Sun Microsystems 开发并由 Oracle 公司发布的一个重要版本,它带来了许多新功能特性,增强了编程语言的能力和性能。 以下是一些 Java 7 的主要新功能特性&#xff1…

基于SSM的体育馆预约管理系统---附源码84196

摘 要 体育馆作为一个重要的运动场所,需要进行预约管理以保证资源的合理利用和场馆秩序的维护。传统的人工预约管理方式存在效率低、容易出错等问题,因此,在互联网高速发展的当下,需要设计和实现一个基于SSM的体育馆预约管理系统&…

关于LLC知识9

1、上图有多条增益曲线,是每种不同的输出负载都对应一条增益曲线,在f1时候每个曲线都汇聚一点,说明只要输出电压频率f1时,不论输出负载是多少,增益是一样的,不受负载影响G1(Lr与Cr发生谐振&…

[单master节点k8s部署]21.EFK日志收集平台介绍

大型系统是一个分布式部署的架构,不同的服务模块部署在不同的服务器上,问题出现时,大部分情 况需要根据问题暴露的关键信息,定位到具体的服务器和服务模块,构建一套集中式日志系统,可以提高 定位问题的效率…

构建自己的语音助手

在我最近发布关于如何构建自己的 RAG 并在本地运行它的帖子之后。今天,我们更进一步,不仅实现了大型语言模型的对话能力,还增加了听力和口语能力。这个想法很简单:我们将创建一个语音助手,让人想起标志性钢铁侠电影中的…

基于asp.net的办公协同管理系统源码分享

今天给大家分享一个asp.net开发的webform框架的办公协同管理系统源码SQLserver数据库 1.主要功能 这个项目是帮助一个学生指导的毕业设计,包含用户登陆、用户管理、车辆 管理、文件管理、个人中心、后台管理、文件上传、人事管理、系统日志等 等模块。2.开发工具及…

【Django-vue-admin学习笔记】页面自动计算日期差额的方法

在许多应用场景中,尤其是在管理系统中,经常需要对日期进行动态计算和展示,以帮助用户了解关键日期的即时状态。例如,在学生宿舍管理系统中,显示学生的退宿倒计时可以帮助管理人员有效监控即将到期的宿舍安排,并及时进行必要的调整。这样的功能不仅提高了管理效率,也增加…

H5接入企微JS-SDK,使用wx.previewFile进行文件预览

最近上项目,需求是做一个附件预览并且可以进行保存到手机、用其他应用打开的需求的需求,用企微的JS-SDK的wx.previewFile就可以满足以上的需求了 详细的可以参考:企业微信官方文档 前端 1、在项目的index.html中添加:jweixin-1.2…

两种用MATLAB绘制色块的方法

绘制色块首先可以想到用填充像素的方式 % 定义图像的尺寸 imageSize 500;% 创建一个 imageSize x imageSize x 3 的矩阵,每个像素都是绿色 % RGB颜色模型中绿色的值为 [0, 1, 0] greenImage zeros(imageSize, imageSize, 3); greenImage(:, :, 2) ones(imageSiz…

Kubeadm快速安装 Kubernetes集群

Kubernetes的基础概念 Kubernetes(通常简称为K8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用程序。Kubernetes 提供了强大的抽象能力,使得开发者能够专注于应用程序的逻辑,而无需担心底层容器的…

某框架路由渗透

前言 某天在互联网平台上看待DWR路由的文章,然后去搜索了一下相关的信息,发现该DWR路由技术挺久远的,因此就简单的学习了一下该路由,然后发现该DWR路由也可能存在漏洞点,因此找了某站进行测试看看是否有无啥收获&…