栈和队列详解

目录

栈的概念及结构:

 栈的实现:

 代码实现:

Stack.h

stack.c

 队列:

概念及结构:

 队列的实现:

 代码实现:

Queue.h

Queue.c

 拓展:

循环队列(LeetCode题目链接):

栈的概念及结构:

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

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

       栈中的数据元素遵守“先进后出/后进先出”的原则。
压栈栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈栈的删除操作叫做出栈。出数据也在栈顶

 “先进后出/后进先出”示意图:

 栈的实现:

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

 代码实现:

Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;//栈顶int capacity;//容量
}ST;
//初始化
void STInit(ST* ps);
//销毁
void STDestroy(ST* ps);
//入栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);
//取栈顶元素
STDataType STTop(ST* ps);
//数据个数
int STSize(ST* ps);
//判空
bool STEmpty(ST* ps);
stack.c
#include"Stack.h"
//初始化
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->capacity = 0;ps->top = 0;
}
//销毁
void STDestroy(ST* ps)
{free(ps->a);ps->a = NULL;ps->capacity = 0;ps->top = 0;
}
//入栈
void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->capacity == ps->top){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* p = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);ps->a = p;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;
}//出栈
void STPop(ST* ps)
{assert(ps);assert(ps->a);assert(!STEmpty(ps));ps->top--;
}
//取栈顶元素
STDataType STTop(ST* ps)
{assert(ps);assert(ps->a);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}
//数据个数
int STSize(ST* ps)
{assert(ps);assert(ps->a);return ps->top;
}
//判空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}

测试代码:

#include"Stack.h"
int main()
{ST p1;STInit(&p1);int i = 0;//入栈for (i = 1; i <= 10; i++){STPush(&p1, i);}printf("栈中数据数量:%d\n", STSize(&p1));//出栈for (i = 0; i < 5; i++){STDataType a = STTop(&p1);printf("%d ", a);STPop(&p1);}printf("\n");printf("栈顶元素:%d\n", STTop(&p1));printf("栈中数据数量:%d\n", STSize(&p1));STDestroy(&p1);return 0;
}

运行结果:

 队列:

概念及结构:

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有“先             进先出/后进后出”的特点。

入队列:进行插入操作的一端称为队尾。

出队列:进行删除操作的一端称为队头。

​​​​​​​“先进先出/后进后出”示意图: 

 队列的实现:

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

 代码实现:

Queue.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;int size;
}Que;
//初始化
void QueueInit(Que* pq);
//销毁
void QueueDestroy(Que* pq);
//入队
void QueuePush(Que* pq, QDataType x);
//出队
void QueuePop(Que* pq);
//取队头
QDataType QueueFront(Que* pq);
//取队尾
QDataType QueueBack(Que* pq);
//判空
bool QueueEmpty(Que* pq);
//有效数据
int QueueSize(Que* pq);
Queue.c
#include"Queue.h"//初始化
void QueueInit(Que* pq)
{assert(pq);pq->head = NULL;pq->tail = NULL;pq->size = 0;
}
//销毁
void QueueDestroy(Que* pq)
{assert(pq);QNode* cur = pq->head;while (cur){QNode* p = cur->next;free(cur);cur = p;}pq->head = NULL;pq->tail = NULL;pq->size = 0;
}
//入队
void QueuePush(Que* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc failed");exit(-1);}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = newnode;pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}pq->size++;
}
//出队
void QueuePop(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));//要有数据if (pq->head->next == NULL)//只有一个节点{free(pq->head);pq->head = NULL;pq->tail = NULL;}else{QNode* cur = pq->head->next;free(pq->head);pq->head = cur;}pq->size--;
}
//取队头
QDataType QueueFront(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}
//取队尾
QDataType QueueBack(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}
//判空 :空返回1,非空返回0
bool QueueEmpty(Que* pq)
{assert(pq);return pq->head == NULL;
}
//有效数据
int QueueSize(Que* pq)
{assert(pq);return pq->size;
}

代码测试:

#include"Queue.h"
int main()
{Que p2;QueueInit(&p2);int i = 0;//入队for (i = 11; i <= 20; i++){QueuePush(&p2, i);}printf("队列中数据数量:%d\n", QueueSize(&p2));//出队for (i = 0; i < 7; i++){QDataType a = QueueFront(&p2);printf("%d ", a);QueuePop(&p2);}printf("\n");printf("队头元素:%d 队尾元素:%d\n", QueueFront(&p2), QueueBack(&p2));printf("队列中数据数量:%d\n", QueueSize(&p2));QueueDestroy(&p2);return 0;
}

运行实例:

 拓展:

循环队列(LeetCode题目链接):

循环队列是一种线性数据结构,其操作表现基于普通队列“先进先出”原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

循环队列可以使用数组实现,也可以使用循环链表实现。

以循环链表实现为例:

 若仅仅是需要几个空间就创建几个空间,则空和满两种情况将无法区分,因此我们可以比实际需要多创建一个空间,这一个多创建出来空间不存储数据,则有如下情况:

 则满和空两种情况就可以区分出来了:front=rear-->空

                                                              rear的下一个=front-->满

同时为了方便取队尾数据,可以定义一个全局变量指向队尾位置(即rear指向位置的前一个)。

具体代码实现:

typedef struct List
{int val;struct List*next;
}list;
typedef struct 
{list*front;list*rear;
} MyCircularQueue;
list*tail;//定义一个全局变量记录rear的前一个
MyCircularQueue* myCircularQueueCreate(int k)
{MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));if (obj == NULL){perror("malloc failed");exit(-1);}obj->front = NULL;obj->rear = NULL;int n = k + 1;while (n--){list* new = (list*)malloc(sizeof(list));if (new == NULL){perror("malloc failed");exit(-1);}new->val = 0;new->next = obj->front;if (obj->front == NULL){obj->front = new;obj->rear = new;}else{obj->rear->next = new;tail=new;obj->rear = obj->rear->next;}}  obj->rear=obj->front;return obj;
}
//判空:空返回真,非空返回假
bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{return obj->front==obj->rear;
}
//是否已满:已满返回真,不满返回假
bool myCircularQueueIsFull(MyCircularQueue* obj)
{return obj->rear->next==obj->front;
}
//插入数据:插入成功返回真,失败返回假
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{assert(obj);if(myCircularQueueIsFull(obj))//已满{return false;}else{obj->rear->val=value;obj->rear=obj->rear->next;tail=tail->next;return true;}
}
//从队列中删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{assert(obj);if(myCircularQueueIsEmpty(obj)){return false;}else{obj->front=obj->front->next;return true;}
}
//获取对首元素
int myCircularQueueFront(MyCircularQueue* obj) 
{assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}return obj->front->val;
}
//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) 
{assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}/*list*cur=obj->front;while(cur->next!=obj->rear){cur=cur->next;}return cur->val;*/return tail->val;
}
//释放空间
void myCircularQueueFree(MyCircularQueue* obj) 
{while(obj->front!=obj->rear){list*Next=obj->front->next;free(obj->front);obj->front=Next;}free(obj->rear);free(obj);
}

 利用数组也可以实现,与链表类似在创建空间是同样需要多创建一个,但是因为队头、队尾没有链接关系,所以利用数组实现时与利用循环链表实现会有所不同:

 与循环链表类似,用数组实现循环队列时,当rear=front时,队列为空;在判断队列是否满时,虽然也是用rear的下一个等于front(即rear+1==front),但是不能单单使用 rear+1==front 判断,因为数组实现时,队首和队尾没有链接关系,当rear在数组最后一个位置时,循环队列已满,但rear+1会越界往后访问,且当front在数组最后一个位置时,删除数据后执行front+1也会出现越界访问的问题,出现错误,因此应想办法让rear和front都在数组范围内变化

观察数组下标,可以让rear+1和front+1都模上k+1,问题就能很好解决。

具体代码实现:

typedef struct
{int k;int front;int rear;int* queue;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k)
{MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));if (obj == NULL){perror("malloc failed");exit(-1);}obj->k = k;obj->front = 0;obj->rear = 0;obj->queue = (int*)malloc(sizeof(int) * (k + 1));if (obj->queue == NULL){perror("malloc failed");exit(-1);}return obj;
}
//判空:空返回真,非空返回假
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{return obj->rear == obj->front;
}
//是否已满:已满返回真,不满返回假
bool myCircularQueueIsFull(MyCircularQueue* obj)
{return (obj->rear + 1) % (obj->k + 1) == obj->front;
}
//插入数据:插入成功返回真,失败返回假
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{assert(obj);if (myCircularQueueIsFull(obj))//已满{return false;}else{obj->queue[obj->rear] = value;obj->rear = (obj->rear + 1) % (obj->k + 1);return true;}
}
//从队列中删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{assert(obj);if (myCircularQueueIsEmpty(obj)){return false;}else{obj->front = (obj->front + 1) % (obj->k + 1);return true;}
}
//获取对首元素
int myCircularQueueFront(MyCircularQueue* obj)
{assert(obj);if (myCircularQueueIsEmpty(obj)){return -1;}return obj->queue[obj->front];
}
//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj)
{assert(obj);if (myCircularQueueIsEmpty(obj)){return -1;}return obj->queue[(obj->rear + obj->k) % (obj->k + 1)];
}
//释放空间
void myCircularQueueFree(MyCircularQueue* obj)
{free(obj->queue);obj->queue = NULL;free(obj);
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年中国倍率型磷酸铁锂出货量及市场需求分析:插电混动汽车用电池为第一大应用市场[图]

由于新能源锂电池市场的竞争极其激烈&#xff0c;各大电池生产厂商不得不细化研发方向&#xff0c;抢占竞争者少、营利性高的细分专业赛道。因此&#xff0c;“自定义”型单体电池应运而生。其主要分为三个大类&#xff0c;分别为高倍率型电池、长寿命型电池和大容量型电池。这…

uni-app实现图片上传功能

效果 代码 <uni-forms-item name"ViolationImg" label"三违照片 :"><uni-file-picker ref"image" limit"1" title"" fileMediatype"image" :listStyles"listStyles" :value"filePathsL…

74HC595驱动7x11点阵屏(LED-7X11-JHM)DEMO

起因 由于我之前做了一个点阵时钟 &#xff0c;但是无奈LED点阵屏价格比较贵&#xff0c;所以想找一个价格较为便宜的点阵来做便宜一点的点阵方案&#xff0c;再淘宝上看到有那种五毛钱一个的7x11的LED点阵&#xff0c;所以就想着试试搞一下这种点阵屏&#xff0c;这个由于是7…

SpringBoot案例-部门管理-根据id查询

目录 根据页面原型&#xff0c;明确需求 查看接口文档 思路分析 接口功能实现 控制层&#xff08;Controller类&#xff09; 业务层&#xff08;Service类&#xff09; 业务类 业务实现类 持久层&#xff08;Mapper类&#xff09; 接口测试 前后端联调 根据页面原型&…

网易互娱出海之旅:大数据平台上云架构设计与实践

2020 年初&#xff0c;随着网易互娱的海外业务增长与海外数据合规的需求&#xff0c;我们开始了网易互娱大数据离线计算平台迁移出海的工作。前期&#xff0c;我们采取了云主机裸机加上高性能 EBS 块存储的方案。但是&#xff0c;这个方案存储费用高昂&#xff0c;成本是国内自…

百度网盘非会员倍速播放(电脑端)

百度网盘非会员倍速播放&#xff08;电脑端&#xff09; 1. 打开edge浏览器&#xff0c;点击右上角的三个点后&#xff0c;选择“扩展” 2. 选择“管理扩展” 3. 选择“获取MicrosoftEdge扩展” 4. 搜索“Global Speed” 5. 选择Global Speed:视频速度控制&#xff0c;然…

概率论与数理统计:第二、三章:一维~n维随机变量及其分布

文章目录 Ch2. 一维随机变量及其分布1.一维随机变量1.随机变量2.分布函数 F ( x ) F(x) F(x)(1)定义(2)分布函数的性质 (充要条件)(3)分布函数的应用——求概率3.最大最小值函数 2.一维离散型随机变量及其概率分布(分布律)3.一维连续型随机变量及其概率分布(概率密度)4.一般类型…

【MOOC】北京理工大学Python网络爬虫与信息提取慕课答案-综合挑出了一些很难评的慕课测验题

1 Requests库中的get()方法最常用&#xff0c;下面哪个说法正确&#xff1f;‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬…

【数据结构与算法】稀疏数组

文章目录 一&#xff1a;为什么会使用稀疏数组1.1 先看一个实际的需求1.2 基本介绍1.2.1 稀疏数组的处理方法1.2.2 数组的举例说明1.2.3 应用实例1.2.4 整体思路分析二维数组转稀疏数组的思路稀疏数组转原始的二维数组的思路 二&#xff1a;代码实现2.1 创建一个原始的11*11二维…

CMake语法中的PUBLIC、PRIVATE、INTERFACE关键字含义

在CMake语法中&#xff0c;经常见到PUBLIC、PRIVATE、INTERFACE关键字&#xff0c;它们是什么意思呢&#xff1f;下面举例说明。 如上图,说明如下&#xff1a; RIVATE&#xff1a;私有的。生成 libhello-world.so时&#xff0c;只在 hello_world.c 中包含了 hello.h&#xff0…

Vision Transformer模型入门

Vision Transformer模型入门 一、Vision Transformer 模型1&#xff0c;Embedding 层结构详解2&#xff0c;Transformer Encoder 详解3&#xff0c;MLP Head 详解 二、ViT-B/16 网络结构三、Hybrid 模型详解四、ViT 模型搭建参数 一、Vision Transformer 模型 总体三个模块&am…

[Vue] Vue2和Vue3的生命周期函数

vue2有11个生命周期钩子, vue3有8个生命周期钩子 从vue创建、运行、到销毁总是伴随着各种事件, 创建、挂载、更新到销毁。 1.vue2系列生命周期 ⑴【beforecreate】实例创建前。 vue完全创建之前&#xff0c;会自动执行这个函数。 ⑵【Created】实例创建后。 这也是个生命…

商品推荐系统浅析 | 京东云技术团队

一、综述 本文主要做推荐系统浅析&#xff0c;主要介绍推荐系统的定义&#xff0c;推荐系统的基础框架&#xff0c;简单介绍设计推荐的相关方法以及架构。适用于部分对推荐系统感兴趣的同学以及有相关基础的同学&#xff0c;本人水平有限&#xff0c;欢迎大家指正。 二、商品…

Qt扫盲-Qt Model/View 理论总结 [下篇]

Qt Model/View 理论总结 [下篇] 一、处理I tem view 中的选择1. 概念1. 当前项目和已选项目 2. 使用选择 model1. 选择项目2. 读取选区状态3. 更新选区4. 选择 model 中的所有项 二、创建新 model1. 设计一个 model2. 只读示例 model1. model 的尺寸2. model 头和数据 3. 可编辑…

【LeetCode】122. 买卖股票的最佳时机 II - 贪婪算法

目录 2023-8-10 10:29:32 122. 买卖股票的最佳时机 II 2023-8-10 10:29:32 没错&#xff0c;还是用双指针思想来套出来的。 感觉步骤很复杂&#xff0c;还调试了半天。 class Solution {public int maxProfit(int[] prices) {int pre 0;int last 1;int maxProfit 0;int c…

Ubuntu18.04搭配无人机仿真环境(ROS,PX4,gazebo,Mavros,QGC安装教程)

Ubuntu18.04搭配无人机仿真环境 ROS环境配置版本安装 gazebo安装Mavrosa安装PX4源码下载和编译运行仿真地面站安装 ROS环境配置 我个人使用了代理环境进行下载。Linux没有代理的可以使用国内源。 清华大学源 sudo sh -c ‘. /etc/lsb-release && echo “deb http://m…

探索极限:利用整数或字符串操作找出翻转后的最大数字

本篇博客会讲解力扣“1323. 6 和 9 组成的最大数字”的解题思路&#xff0c;这是题目链接。 对于这道题目&#xff0c;我会讲解2种解题思路&#xff0c;分别是直接操作整数&#xff0c;和利用字符串操作。希望大家通过本题学习关于整数和字符串的技巧。 显然&#xff0c;这道题…

《华为认证》L2TP VPN配置

配置接口ip地址&#xff0c;并且将防火墙的接口加入对应的安全区域 。 LNS的G1/0/0 IP为202.1.1.1 1、配置LNS的缺省路由&#xff1a; ip route-static 0.0.0.0 0.0.0.0 202.1.1.2 2、通过WEB 界面配置防火墙的 L2TP VPN 浏览器输入&#xff1a; https://202.1.1.1:8443/def…

HTML详解连载(2)

HTML详解连载&#xff08;2&#xff09; 专栏链接 [link](http://t.csdn.cn/xF0H3)下面进行专栏介绍 开始喽超链接作用代码示例解释经验分享 音频标签代码示例注意强调 视频标签代码示例注意强调 列表作用&#xff1a;布局内容排列整齐的区域。分类&#xff1a;无序列表&#x…

商业智能BI,如何区别联机事务处理(OLTP)和联机分析处理(OLAP)

商业智能(Business Intelligence&#xff0c;简称&#xff1a;BI)&#xff0c;又称商业智慧或商务智能&#xff0c;指用现代数据仓库技术、线上分析处理技术、数据挖掘和数据展现技术进行数据分析以实现商业价值。 商业智能BI - 派可数据数据可视化分析平台 定义为下列软件工具…