☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼

准备好了么

目录:

一·用两个队列实现栈:

1·思路: 

2·画图理解:

3·代码解答: 

二·用两个栈实现队列:

 1·思路:

  2·画图理解:

3·代码解答:

三·设计循环队列: 

1·思路: 

2·画图理解:

3·代码解答:


一·用两个队列实现栈:

源:oj链接:. - 力扣(LeetCode)​​​​​​

1·思路: 

我们首先调用创建好的队列代码,然后假设令这两个队列作为一个栈,由于我们画图可以得出一个结论:

①当有两个空队列的时候,我们push时随便push,一直往不为空的队列里面push。

②当我们要移除并返回栈顶元素的时候,我们要把不为空的队列里n-1个元素push到另一个空的队列里面,最后得到将要pop与return的元素。

③只返回栈顶元素只需要返回不为空队列的尾指针指向的元素即可。

④判空的话,就是两个队列都为空才行。

2·画图理解:

3·代码解答: 

typedef int qdatatype;
typedef struct Qnode {struct Qnode* next;qdatatype data;
}Qnode;
typedef struct queue {int size;Qnode* head;Qnode* tail;
}queue;void Queueinit(queue* p) {assert(p);p->head =p->tail = NULL;p->size = 0;
}void Queuedestroy(queue* p) {assert(p);Qnode* cur = p->head;while (cur) {Qnode* next = cur->next;free(cur);cur = next;}p->size = 0;p->tail = p->head = NULL;
}void Queuebackpush(queue* p, qdatatype x) {assert(p);Qnode* newnode = (Qnode*)malloc(sizeof(Qnode));if (newnode == NULL) {perror(malloc);return;}newnode->next = NULL;newnode->data = x;if (p->tail == NULL) {p->head = p->tail = newnode;}else {p->tail->next = newnode;p->tail = newnode;}p->size++;}void Queuefrontpop(queue* p) {assert(p);assert(p->size > 0);if (p->head->next == NULL) {free(p->head);p->head = p->tail = NULL;}else {Qnode* next = p->head->next;free(p->head);p->head = next;}p->size--;
}qdatatype Queuefrontdata(queue* p) {assert(p);assert(p->size > 0);return p->head->data;
}qdatatype Queuebackdata(queue* p) {assert(p);assert(p->size > 0);return p->tail->data;
}int Queuesize(queue* p) {assert(p);return p->size;
}bool QueueEmpty(queue* p) {assert(p);return p->size == 0;
}//以上是引用的队列的创建typedef struct {queue p1;queue p2;} MyStack;//这里定义了一个结构体类型:我的栈:里面放了两个队列结构体类型的变量MyStack* myStackCreate() {MyStack*pst=(MyStack*)malloc(sizeof(MyStack));Queueinit(&(pst->p1));Queueinit(&(pst->p2));return pst;}//在这里将MyStack结构体里面的两个队列初始化,并得到MyStack类型的指针void myStackPush(MyStack* obj, int x) {if( !QueueEmpty(&(obj->p1))){Queuebackpush(&(obj->p1),x);}else{Queuebackpush(&(obj->p2),x);}//这里我们在两个队列里面插入数据,故由于让看起来像栈的形式,我们就找有数据的队列插入新的数据即
//找不为空的队列插入}int myStackPop(MyStack* obj) {//这里我们用假设法来得到空与非空队列queue*empty=&(obj->p1);queue*noempty=&(obj->p2);if(!QueueEmpty(&(obj->p1))){//如果假设不成立执行下面noempty=&(obj->p1);empty=&(obj->p2);}//以上操作我们就可以得到noempty empty 分别为空与非空的队列while( Queuesize(noempty)>1){Queuebackpush(empty,Queuefrontdata(noempty));Queuefrontpop(noempty);}//下面防止找不到要得到的栈顶元素,我们在pop之前要先保存一下int data=Queuefrontdata(noempty);Queuefrontpop(noempty);return data;}//首先我们要找到空的队列,然后把非空队列获得头部元素进行插到原来空的队列里,插入n-1个int myStackTop(MyStack* obj) {if( !QueueEmpty(&(obj->p1))){return Queuebackdata(&(obj->p1));}else{return Queuebackdata(&(obj->p2));}//这里返回栈顶元素即就是我们不为空的队列的队尾元素}bool myStackEmpty(MyStack* obj) {return QueueEmpty(&(obj->p1))&&QueueEmpty(&(obj->p2));
}void myStackFree(MyStack* obj) {Queuedestroy(&(obj->p1));Queuedestroy(&(obj->p2));free(obj);obj=NULL;
//这里由于我们在 MyStack里开辟了两个队列的链表类型空间故需要先释放掉,
//再释放obj}

测试: 

​
int main()
{MyStack* st = myStackCreate();myStackPush(st, 1);myStackPush(st, 2);int ret = myStackTop(st);printf("%d",ret);mystackFree(st);return 0;
}​

二·用两个栈实现队列:   

源:oj链接:. - 力扣(LeetCode)​​​​​​

 1·思路:

这里首先建立两个栈作为MyQueue,大致思路和两个队列实现栈相差不大,这里只不过是调用的事先创建的队列改成栈了,此外再删去元素的时候会多排序一次。

①push:还是找空的栈然后,依次入栈

②pop:类似于上面的实现,但是当我们把n-1个元素放到另一个空栈里面顺序与原来是相反的故需要颠倒一下,此时就要再入一次栈入到原栈里,(先保存再返回,再删除)。

③peek:由于我每次使用函数的时候,这两个栈必然有一个空有一个非空,只需要返回非空栈的下标为0的元素即可。

④empty:这里判空也是两个均为空。

  2·画图理解:

3·代码解答:

typedef int typedata;
typedef struct stack {typedata* a;int top;int capacity;} ST;void STinit(ST* p) {assert(p);p->a = NULL;p->capacity = p->top = 0;
}
void STpush(ST* p,typedata x) {assert(p);//扩容if (p->top == p->capacity) {int newcapacity = p->capacity == 0 ? 4 : (p->capacity) * 2;typedata* tmp = (typedata*)realloc(p->a, sizeof(typedata)*newcapacity);if (tmp == NULL) {perror("realloc");return;}p->a = tmp;p->capacity = newcapacity;}p->a[p->top] = x;p->top++;
}
void STpop(ST* p) {assert(p);assert(p->top);p->top--;}typedata STTop(ST* p) {assert(p);assert(p->top);return p->a[p->top - 1];}
bool STempty(ST* p) {assert(p);return p->top == 0;
}
int STsize(ST* p) {assert(p);return p->top;
}
void STdestroy(ST* p) {assert(p);free(p->a);p->a = NULL;p->capacity = p->top = 0;
}//以上是对栈的实现typedef struct {ST s1;ST s2;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* q=(MyQueue* )malloc(sizeof(MyQueue));STinit(&(q->s1));STinit(&(q->s2));return q;
//在MyQueue内开辟两个栈的空间}void myQueuePush(MyQueue* obj, int x) {if(!STempty(&(obj->s1))){STpush(&(obj->s1),x);}else{STpush(&(obj->s2),x);}//这里也是找到非空栈进行插入数据
}int myQueuePop(MyQueue* obj) {ST*empty=&(obj->s1);ST*noempty=&(obj->s2);if(!STempty(&(obj->s1))){noempty=&(obj->s1);empty=&(obj->s2);}//通过假设法得到真实的非空与空的栈while(STsize(noempty)>1){STpush(empty,STTop(noempty));STpop(noempty);}//首先第一个循环是得到n-1个数据到原来空的栈里面,但是顺序是反的int data=STTop(noempty);STpop(noempty);//在这里保存队列即栈的第一个元素,并把它popwhile(STsize(empty)>0){STpush(noempty,STTop(empty));STpop(empty);}//通过再一个循环把它重新插入到原来的栈里,顺序恢复return data;}int myQueuePeek(MyQueue* obj) {if(!STempty(&(obj->s1))){return obj->s1.a[0];}else{return  obj->s2.a[0];}
}
//直接返回栈的首元素即队首元素
bool myQueueEmpty(MyQueue* obj) {return STempty(&(obj->s1))&&STempty(&(obj->s2));
}void myQueueFree(MyQueue* obj) {STdestroy(&(obj->s1));STdestroy(&(obj->s2));free(obj);obj=NULL;}/*** Your MyQueue struct will be instantiated and called as such:* MyQueue* obj = myQueueCreate();* myQueuePush(obj, x);* int param_2 = myQueuePop(obj);* int param_3 = myQueuePeek(obj);* bool param_4 = myQueueEmpty(obj);* myQueueFree(obj);
*/

 测试:

int main() {MyQueue* m = myQueueCreate();myQueuePush(m, 1);myQueuePush(m, 2);myQueuePush(m, 3);int ret = myQueuePop(m);printf("%d ", ret);int n=myQueuePeek(m);printf("%d ", n);return 0;
}

三·设计循环队列:
 

 

源:oj链接:. - 力扣(LeetCode)​​​​​​

1·思路: 

设计循环队列,首先把它设计成一个数组的形式来循环利用,这里会涉及到判空与判满如何进行,

那么我们有两种方法解决,一个是进出队列用size记录,一个是额外多开辟一个空间,,我们选择用后者。比如设置长度为k,那么就要开辟k+1个空间。而多出来的空间我们不放数据用tail指向这个空的空间。(下面的head与tail实则是下标,把它假想为指针)

 ①MyCircularQueue:创建一个结构体存放队列要开辟的长度k,头尾指针以及int类型的指针a。

②myCircularQueueFront:找头,可以直接对a[head]去访问。

③myCircularQueueRear:访问尾指针前一个数据的话由于可能会存在tail为0,那么上一个就是-1,明显是不可能的,故需要转化,可以把它tail-1直接变成k,也可以tail-1后+(k+1)%(k+1).

④myCircularQueueEnQueue:插入数据先判是否full,没有的话,就放入tail++,而可能存在为k+1.那么就把它变为0,或者直接(++tail)%(k+1)。

⑤ myCircularQueueDeQueue:这里我们画图可以发现删除数据只需要head++,而tail不用变化,但是head++,当过界时候把它变为0。

⑥myCircularQueueIsEmpty:头尾指针指向同一个处,即head==tail。

⑦myCircularQueueIsFull:画图可以知道每每当填满数据的时候tail+1==head(不包括越界改变的情况),故我们还是可以在tail到k+1,把它变为0,看是否与head相同,也可以(tail+1)%(k+1)看是否==head。

2·画图理解:

3·代码解答:


typedef struct {int head;int tail;int k;//要开辟的队列长度int *a;} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {if(k<0){return NULL;}MyCircularQueue*q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));int *m=(int*)malloc(sizeof(int)*(k+1));q->head=q->tail=0;q->a=m;q->k = k;//将结构体里的k初始化为队列长度kreturn q;}
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);//这里由于提前调用未定义的函数故需要在前面声明bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj)){return false;}else{// obj->a[obj->tail]=value;// obj->tail++;//  if(obj->tail==obj->k+1){// obj->tail=0;//这里有一个情况当tail+1到达数组超过数组最大额度就变为0obj->a[obj->tail]=value;obj->tail++;obj->tail%=obj->k+1;//这里取模可以简化上面的判断}return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return false;}obj->head++;// obj->a[obj->tail++];// if(obj->tail==obj->k+1){//     obj->tail=0;// }if(obj->head==obj->k+1){obj->head=0;}return true;//这里我们要删出队列的第一个元素,那么只需要head++(这里也要考虑越界变0),然后tail不变即可}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}return obj->a[obj->head];}int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}
//     if(obj->tail==0){
//      return obj->a[obj->k];
//     }
//   else{
//     return obj->a[obj->tail-1];
//   }//这里是返回tail的上一个数据,故可能会出现tail为零那么tail-1=-1;实际为k//简化:return obj->a[(obj->tail-1+(obj->k+1))%(obj->k+1)];}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {if(obj->head==obj->tail){return true;}else{return false; }
}bool myCircularQueueIsFull(MyCircularQueue* obj) {// if(obj->tail==obj->k&&obj->head==0){//     return true;// }// if(obj->tail+1==obj->head){//     return true;// }//     return false;/*这里判断是否满,我们画图可以得到在多开辟一个空间的时候,每当tail+1=head就满了,考虑到可能tail+1为-1,故进行了讨论判断*///简化:return (obj->tail+1)%(obj->k+1)==obj->head;//%(k+1)可以将越界的下标变成-1
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);obj->a=NULL;free(obj);obj=NULL;//先释放掉开辟的数组空间内存,再把结构体的空间释放,指针置空
}/*** Your MyCircularQueue struct will be instantiated and called as such:* MyCircularQueue* obj = myCircularQueueCreate(k);* bool param_1 = myCircularQueueEnQueue(obj, value);* bool param_2 = myCircularQueueDeQueue(obj);* int param_3 = myCircularQueueFront(obj);* int param_4 = myCircularQueueRear(obj);* bool param_5 = myCircularQueueIsEmpty(obj);* bool param_6 = myCircularQueueIsFull(obj);* myCircularQueueFree(obj);
*/

测试:

int main() {MyCircularQueue* m = myCircularQueueCreate(3);myCircularQueueEnQueue(m, 1);myCircularQueueEnQueue(m, 2);myCircularQueueEnQueue(m, 3);myCircularQueueEnQueue(m, 4);printf("%d ", myCircularQueueRear(m));myCircularQueueIsFull(m);myCircularQueueDeQueue(m);myCircularQueueEnQueue(m, 4);printf("%d ", myCircularQueueRear(m));myCircularQueueFree(m);return 0;
}

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

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

相关文章

synchronized 使用及实现原理

synchronized 关键字 如何使用 synchronized 关键字的使用方式主要有下面 3 种&#xff1a; 修饰实例方法 修饰静态方法 修饰代码块 1、修饰实例方法 &#xff08;锁当前对象实例&#xff09; 给当前对象实例加锁&#xff0c;进入同步代码前要获得 当前对象实例的锁 。 …

Vitis HLS 学习笔记--AXI_STREAM_TO_MASTER

目录 1. 简介 2. 示例 2.1 示例功能介绍 2.2 示例代码 2.3 顶层函数解释 2.4 综合报告&#xff08;HW Interfaces&#xff09; 2.5 关于TKEEP和TSTRB 2.6 综合报告&#xff08;SW I/O Information&#xff09; 3. 总结 1. 简介 本文通过“<Examples>/Interface…

pytest(二)

1.pytest-html⽣成报告 Pytest-HTML 是⼀个插件&#xff0c;它可以⽣成漂亮且易于阅读的 HTML 测试报告。下⾯是使⽤ pytest-html ⽣成报告的步骤&#xff1a; 1. 安装 pytest-html 插件&#xff1a; pip install pytest-html 2. 运⾏测试并⽣成报告 pytest --htmlr…

5月13号作业

使用消息队列实现的2个终端之间的互相聊天 并使用信号控制消息队列的读取方式&#xff1a; 当键盘按ctrlc的时候&#xff0c;切换消息读取方式&#xff0c;一般情况为读取指定编号的消息&#xff0c;按ctrlc之后&#xff0c;指定的编号不读取&#xff0c;读取其他所有编号的消息…

CCF-Csp算法能力认证,202209-1如此编码(C++)含解析

前言 推荐书目&#xff0c;在这里推荐那一本《算法笔记》&#xff08;胡明&#xff09;&#xff0c;需要PDF的话&#xff0c;链接如下 「链接&#xff1a;https://pan.xunlei.com/s/VNvz4BUFYqnx8kJ4BI4v1ywPA1?pwd6vdq# 提取码&#xff1a;6vdq”复制这段内容后打开手机迅雷…

python内置函数exec()和eval()区别

在Python中&#xff0c;eval() 和 exec() 都是内置函数&#xff0c;用于执行存储在字符串或对象中的Python代码&#xff0c;但它们之间也有一些区别。 eval() 语法&#xff1a;eval(expression, globalsNone, localsNone) expression&#xff1a;需要求值的字符串表达式。可…

到底考不考CISP?纠结的看过来

专业认证如CISP&#xff08;注册信息安全专业人员&#xff09;成为了衡量专业水平的重要标准。 CISP的含金量懂的都懂&#xff0c;然而&#xff0c;是否要投入时间、精力和金钱去追求这样一个认证&#xff0c;对于许多人来说&#xff0c;依然是一个值得深思的问题。 那么到底…

第十一届蓝桥杯大赛软件类决赛 Java C 组

文章目录 发现宝藏【考生须知】试题 A: 美丽的 2试题 B: 合数个数试题 C: 扩散试题 D: 阶乘约数试题 E: 本质上升序列试题 F 天干地支试题 G 皮亚诺曲线距离试题 H 蓝肽子序列试题 I: 画廊试题 J 答疑 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&a…

Linux 操作系统多路IO复用

1.多路IO复用 多路I/O复用是通过一种机制&#xff0c;可以监视多个描述符&#xff0c;一旦某个描述符就绪&#xff08;一般是读就绪或者写就绪&#xff09;&#xff0c;能够通知程序进行相应的读写操作。 这个机制能够通过select/poll/eroll等来使用。这些函数都可以同时监视多…

文件流-二进制文件(中北大学-程序设计基础(2))

目录 题目 源码 结果示例 题目 建立两个二进制磁盘文件f1.dat,f2.dat&#xff0c;编程实现以下工作&#xff1a; &#xff08;1&#xff09;将20个整数&#xff08;可在程序中初始化&#xff09;&#xff0c;分别存放到两个磁盘文件中&#xff0c;前10个放到f1.dat中&…

Linux下网络命令

目录 需求1-查看本机是否存在22端口解法1解法2解法3 需求2-查看其他主机是否存在22端口解法1解法2解法3 需求3-查看TCP连接解法1/2 需求4-统计80端口tcp连接次数解法 需求5-查看总体网络速度解法 需求6-查看进程流量解法 需求7-dns解法 需求8-traceroute到baidu解法 需求9-查看…

任务通知理论和使用

文章目录 一、任务通知是什么&#xff1f;1.1任务通知的优势1.2任务通知的限制1.3通知状态和通知值 二、任务通知的使用2.1任务通知使用_轻量级信号量2.2任务通知使用_轻量级队列2.3任务通知使用_轻量级事件组 一、任务通知是什么&#xff1f; 我们使用队列、信号量、事件组等…

浅析视频汇聚EasyCVR视频融合云平台在机场安防智能检测建设中的应用

一、背景 机场作为国家交通枢纽和对外开放的窗口&#xff0c;其安全运行直接关系到乘客的生命安全、国家形象以及社会经济稳定。随着全球航空业的快速发展和人们出行需求的持续增长&#xff0c;机场作为重要的交通枢纽&#xff0c;其客流量和货运量均呈现出快速增长的态势。然而…

HCIP的学习(16)

BGP的状态机 ​ OSPF的状态机是在描述整个协议的完整工作过程&#xff0c;而BGP的状态机仅描述的是对等体关系建立过程中的状态变化。-----因为BGP将邻居建立过程以及BGP路由收发过程完全隔离。 ​ IGP协议在启动后&#xff0c;需要通过network命令激活接口&#xff0c;从而使…

SD-WAN供应商选择指南

企业网络日益演变&#xff0c;尤其是跨国企业、出海电商和外贸企业&#xff0c;其网络需求变得愈发复杂多样。SD-WAN技术因此备受瞩目&#xff0c;成为连接分支机构和数据中心的关键解决方案。然而&#xff0c;市面上的SD-WAN供应商众多&#xff0c;如何选择适合的服务商成为了…

gitignore配置不生效记录

第一种可能性&#xff1a; 在你所有的文件都通过了git add . 命令的情况下&#xff0c;使用指令git rm -r --cached .进行缓存清除&#xff0c;完成之后&#xff0c;再次通过git add . 然后通过git status去看提交的文件都有哪些。 第二种可能性 如果上面的不行就是你添加的…

【机器学习】Scikit-Learn:Python机器学习的瑞士军刀

Scikit-Learn&#xff1a;Python机器学习的瑞士军刀 一、Scikit-Learn简介二、Scikit-Learn的核心功能数据预处理模型选择模型评估模型部署 三、Scikit-Learn的中文社区与API四、代码实例&#xff1a;使用Scikit-Learn进行鸢尾花数据集分类 在当今这个数据驱动的时代&#xff0…

论文《Deep graph tensor learning for temporal link prediction》阅读

论文《Deep graph tensor learning for temporal link prediction》阅读 论文概况IntroductionRelated work动态图表示学习图张量表示 Preliminary张量生成建模 深度图张量学习模型A.基于图紧凑的空间表示B.时间模式表示C.时空特征聚合D.损失函数 实验数据集对比实验消融实验参…

鸿蒙ArkUI开发:常用布局【交叉轴】

交叉轴 垂直于主轴方向的轴线。Row容器交叉轴为纵向&#xff0c;Column容器交叉轴为横向。通过alignItems属性设置子元素在交叉轴&#xff08;排列方向的垂直方向&#xff09;上的对齐方式alignSelf属性用于控制单个子元素在容器交叉轴上的对齐方式&#xff0c;其优先级高于al…

M 有效算法

M 有效算法 本题考验二分知识&#xff0c;思路是二分k的取值&#xff0c;就按第一组样例来说当我们k取值为1的时候我们遍历数组想让|8-x|<k1的话x的取值范围是7-9&#xff0c;想让|3-x|<k2的话x的取值范围是1-5&#xff0c;两者x的区间不重合&#xff0c;说明肯定没有x能…