栈和队列题目练习

本节小编选了两道题来加深对栈和队列的认识理解!

有效的括号

方法1:直接用栈的结构(动态数组)

本题可以用栈这个结构来解答,将'(','{','['  左括号压入栈中,然后取出栈顶元素与右括号')','}',']'匹配。不匹配的话,返回false,我们同时也要考虑空集的情况,即栈中元素为空,则返回false。

因为本题使用c语言写的,所以需要手撕栈的结构,可以运用上篇博客所写的栈的代码。

typedef  char  datatype;
typedef struct stack {datatype* a;int top;//栈顶int capacity;
}ST;
void STInit(ST* pst){assert(pst);pst->a = NULL;//top指向栈顶数据的下一个位置,可以理解为下标pst->top = 0;pst->capacity = 0;
}
void STDestory(ST* pst) {assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}
//容量检查
void Checkcapacity(ST* pst) {assert(pst);if (pst->top == pst->capacity) {int newcapacity = pst->capacity==0?4:pst->capacity * 2;datatype* temp = (datatype*)realloc(pst->a, newcapacity * sizeof(datatype));if (temp == NULL) {perror("relloc fail");return;}pst->a = temp;pst->capacity = newcapacity;}
}
//入栈和出栈
void STPush(ST* pst, datatype x) {assert(pst);Checkcapacity(pst);pst->a[pst->top] = x;pst->top++;
}
void STPop(ST* pst) {assert(pst);assert(pst->top>0);pst->top--;
}
//获取栈顶数据
datatype STTop(ST* pst) {assert(pst);assert(pst->top > 0);return pst->a[pst->top-1];
}
//判空
bool STEmpty(ST* pst) {assert(pst);return pst->top == 0;//表达式判断
}
//栈的数据个数
int STSize(ST* pst) {assert(pst);return pst->top;
}
bool isValid(char* s) {ST st;STInit(&st);while(*s){//左括号入栈if(*s=='('||*s=='{'||*s=='['){STPush(&st,*s);}else{//空集的情况,入栈结束后检查是否为空,if(STEmpty(&st)){STDestory(&st);return false;}char top=STTop(&st);STPop(&st);//通过括号不匹配的情况判断if((top=='('&& *s!=')') ||(top=='['&& *s!=']')||(top=='{'&& *s!='}')){STDestory(&st);return false;//STPop(&st);}}s++;}
//看最后是否栈为空,探讨左右括号数量不匹配的情况。bool ret=(STEmpty(&st));STDestory(&st);return ret;
}

方法2:通过数组模拟栈来实现

使用一个字符数组作为栈,通过使用top标记栈顶的位置来实现栈的操作。在遍历字符串的过程中,遇到左括号就将其压入栈中,遇到右括号就与栈顶元素进行匹配。如果匹配成功,则将栈顶元素出栈,否则返回false。最后,如果栈为空,则说明所有的括号都匹配成功,返回true;否则,返回false。

bool isValid(char* s) {char stack[10000];int top = -1;int len = strlen(s);for (int i = 0; i < len; i++) {if (s[i] == '(' || s[i] == '{' || s[i] == '[') {stack[++top] = s[i];} else {if (top == -1) {return false;}if ((s[i] == ')' && stack[top] == '(') || (s[i] == '}' && stack[top] == '{') || (s[i] == ']' && stack[top] == '[')) {top--;} else {return false;}}}return top == -1;
}

设计循环队列

方法1:使用动态数组

通过画图发现,当head==tail时,既是队列为空的条件,也是队列满的条件,所以我们可以通过增加一个空间来辅助判满,当tail+1=head时。还有另外一个方法,通过定义size变量,当size大小等于k时,也是队列满的时候。

在后续解决回绕的问题时,我们多次采用取模的方法,因为一个数除以比他大的数,取模后大小不变,当相等时,模为0,刚好回到起点处,完美的解决了回绕问题。

//循环队列先进先出
typedef struct {int *arr;int head;int tail;//指向尾下一个int k;
} MyCircularQueue;//创建循环队列
MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多开辟一个空间obj->arr=(int*)malloc(sizeof(int)*(k+1));obj->head=0;obj->tail=0;obj->k=k;return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//头尾相等时队列为空return (obj->head)==obj->tail;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {//当tail+1=head时,为满,通过取模解决回绕问题return((obj->tail+1)%(obj->k+1))==obj->head;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//队列满的时候,返回falseif(myCircularQueueIsFull(obj))return false;//插入一个数据,tail后移obj->arr[obj->tail]=value;obj->tail++;//解决回绕,重头再来obj->tail %=(obj->k+1);return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return false;//head前进,删除数据obj->head++;//解决回绕问题obj->head %=(obj->k+1);return true;
}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->arr[obj->head];
}int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;else//分类讨论取尾元素return obj->tail==0?obj->arr[obj->k]:obj->arr[obj->tail-1];//return obj->arr[(obj->tail-1+obj->k+1)%(obj->k+1)];//取模的方法很巧妙
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->arr);free(obj);
}

方法2:双向链表实现

使用双向链表实现,其中每个节点(Node)包含一个整数值(val),以及指向前一个节点和后一个节点的指针(prev和next)。循环队列(MyCircularQueue)包含一个指向队列头部和尾部的指针(head和tail),以及队列的大小(size)和容量(capacity)。

//节点建立
typedef struct Node {int val;struct Node* prev;struct Node* next;
} Node;
//双向链表实现队列
typedef struct {Node* head;Node* tail;int size;int capacity;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->head = NULL;obj->tail = NULL;obj->size = 0;obj->capacity = k;return obj;
}
//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->size == 0;
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {return obj->size == obj->capacity;
}
//插入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if (myCircularQueueIsFull(obj)) {return false;}Node* newNode = (Node*)malloc(sizeof(Node));newNode->val = value;newNode->prev = NULL;newNode->next = NULL;//队列为空时if (myCircularQueueIsEmpty(obj)) {obj->head = newNode;obj->tail = newNode;newNode->next = newNode;newNode->prev = newNode;} // 不为空时else {newNode->prev = obj->tail;newNode->next = obj->head;obj->tail->next = newNode;obj->head->prev = newNode;obj->tail = newNode;}obj->size++;return true;
}
//数据的删除
bool myCircularQueueDeQueue(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj)) {return false;}Node* del = obj->head;if (obj->size == 1) {obj->head = NULL;obj->tail = NULL;} else {obj->head = obj->head->next;obj->head->prev = obj->tail;obj->tail->next = obj->head;}obj->size--;free(del);return true;
}
//头数据
int myCircularQueueFront(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj)) {return -1;}return obj->head->val;
}
//尾数据
int myCircularQueueRear(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj)) {return -1;}return obj->tail->val;
}
//队列销毁
void myCircularQueueFree(MyCircularQueue* obj) {Node* curr = obj->head;while (curr != obj->tail) {Node* next = curr->next;free(curr);curr = next;}obj->tail=NULL;free(obj);
}

补充方法3:

使用链表(单链表)-投机取巧哈哈哈

不过这种方法没有关系到循环队列,也能通过该题目。

可以用链表实现队列,用链表实现队列则较为简单,因为链表可以在 O(1)时间复杂度完成插入与删除。入队列时,将新的元素插入到链表的尾部;出队列时,将链表的头节点返回,并将头节点指向下一个节点。

循环队列的属性如下:

head:链表的头节点,队列的头节点。
tail:链表的尾节点,队列的尾节点。
capacity:队列的容量,即队列可以存储的最大元素数量。
size:队列当前的元素的数量。

相比较与数组,我们使用了size的方法来判断队列为空为满的状态,

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//中间节点创建和函数主体
typedef struct node {int val;struct node* next;
} node;
//循环队列先进先出
typedef struct {node* head;node* tail;int size;int capacity;
} MyCircularQueue;//创建循环队列
MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->head=obj->tail=NULL;obj->size=0;obj->capacity=k;return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {if(obj->size==0)return true;elsereturn false;
//return obj->size==0;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {return obj->size==obj->capacity;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj))return false;node* newnode=(struct node*)malloc(sizeof(node));newnode->val=value;newnode->next=NULL;if(obj->size==0){obj->head=newnode;obj->tail=newnode;}else{obj->tail->next=newnode;obj->tail=newnode;}obj->size++;return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return false;node*del=obj->head;obj->head=obj->head->next;free(del);obj->size--;return true;}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->head->val;
}int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->tail->val;
}void myCircularQueueFree(MyCircularQueue* obj) {node* curr = obj->head;while (curr != NULL) {node* next = curr->next;free(curr);curr = next;}obj->size = obj->capacity = 0;obj->head = obj->tail = NULL;free(obj);
}//手动测试部分
int main() {MyCircularQueue* obj = myCircularQueueCreate(5);myCircularQueueEnQueue(obj, 1);myCircularQueueEnQueue(obj, 2);myCircularQueueEnQueue(obj, 3);myCircularQueueEnQueue(obj, 4);myCircularQueueEnQueue(obj, 5);printf("%d\n", myCircularQueueRear(obj));printf("%d\n", myCircularQueueFront(obj));myCircularQueueDeQueue(obj);printf("%d\n", myCircularQueueFront(obj));myCircularQueueFree(obj);return 0;
}

OK,本节内容到此结束,各位友友留下三连和评论吧,有更好的方法希望各位佬私信交流!!!

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

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

相关文章

【Qt】【模型视图架构】 在项目视图中启用拖放

文章目录 1. 在便捷类中启用拖放2. 在模型/视图类中启用拖放 模型/视图框架支持Qt的拖放应用。 列表、表格和树中的项目可以在视图中被拖拽&#xff0c;数据作为MIME编码的数据被导入和导出。标准视图可以自动支持内部的拖放。 默认视图的拖放功能并没有被启用&#xff0c;如果…

opencv进阶 ——(八)图像处理之RMBG模型AI抠图

BRIA.AI团队于HuggingFace开源了一个基于ISNet背景移除模型RMBG-1.4&#xff0c;它可以有效对前景与背景进行分离。RMBG-1.4在精心构建的数据集上训练而来&#xff0c;该数据包含常规图像、电商、游戏以及广告内容&#xff0c;该方案达到了商业级性能&#xff0c;但仅限于非商业…

【PHP项目实战训练】——laravel框架的实战项目中可以做模板的增删查改功能(1)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【管理咨询宝藏120】顶级咨询公司领导管控优化设计方案

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏120】顶级咨询公司领导管控优化设计方案 【格式】PDF版本 【关键词】人力资源、组织管控、领导力 【核心观点】 - 管的过细” “高层的管理要往…

【排序】冒泡排序

在我们的生活中&#xff0c;到处都离不开排序的作用&#xff0c;考试分数要排序&#xff0c;商场购物要排序&#xff0c;可以说排序对我们来说处处存在&#xff0c;那么从本章开始&#xff0c;我将要依次分享一些排序方法&#xff0c;从易到难&#xff0c;包括冒泡&#xff0c;…

随身wifi和手机流量卡,你知道该怎么选吗?

网络已经成为我们这个时代的代名词&#xff01; 那么&#xff0c;在上网的时代&#xff0c;我们有很多问题都要考虑&#xff0c;比如如何选择上网方式&#xff0c;是选择一张流量卡&#xff0c;还是一个随身WIFI&#xff1f; 听小编一句劝&#xff0c;先不要着急买&#xff0c…

接口测试工具:Postman的下载安装及使用

1 Postman 介绍 1.1 Postman 是什么 Postman 是一款功能超级强大的用于发送 HTTP 请求的 测试工具 做 WEB 页面开发和测试的人员常用工具 创建和发送任何的 HTTP 请求(Get/Post/Put/Delete...) 1.2 Postman 相关资源 1.2.1 官方网站&#xff1a;https://www.postman.com/ …

sde the Upgrade Geodatabase tool to install/upgrade system tables (-64).

数据库端迁移sde导入后&#xff0c;在sde端启动服务报错&#xff1a; ------------------------------------------------------- ArcSDE 10.0 for Oracle11g Build 685 Fri May 14 12:05:43 2010 ------------------------------------------------------- ST_Geometry Sc…

Java——面向对象初阶

前言&#xff1a; Java面向对象相关讲解 文章目录 一、面向对象二、类与对象三、封装四、构造方法及重载五、this关键字六、基本数据类型和引用数据类型七、JavaBean类 一、面向对象 面向对象&#xff08;Object-Oriented Programming, OOP&#xff09;是一种编程范式&#xff…

C++第二十二弹---vector深度剖析及模拟实现(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、容量操作 2、内容修改操作 3、打印函数 4、迭代器失效 4.1、什么是迭代器失效 4.2、哪些操作会引起迭代器失效 总结 1、容量操作 size()…

Idea的相关操作

1、关闭自动更新 点击左上角File->Setting&#xff0c;进入配置页面&#xff0c;点击Appearance & Behavior > System Settings > Updates&#xff0c;取消勾选更新选项&#xff0c;如图&#xff1b; 2、代码提示忽略大小写 点击左上角File->Setting&#xf…

用Unityhub安装unity2018.3.0和vuforia

打开下载网址 https://unity.cn/releases/full/2018 选择2018.3.x 找到2018.3.0后&#xff0c;点击从UnityHub下载 然后unityhub会弹出安装界面 只勾选这两个&#xff0c;其余的全部取消勾选&#xff0c;默认勾选上的也取消掉&#xff0c;然后点击安装

【数据分享】2009-2022年我国省份级别的轨道交通相关指标(20多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2022年《中国城市建设统计年鉴》整理的2006—2022年我国省份级别的市政设施水平相关指标、2006-2022年我国省份级别的各类建设用地面积数…

String 类

目录&#xff1a; 一. 认识 String 类 二. String 类的基本用法 三. String对象的比较 四.字符串的不可变性 五. 认识 StringBuffer 和 StringBuilder 一. 认识 String 类&#xff1a; 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者…

Unity2D横版摄像机跟随

在Unity2D横版游戏中&#xff0c;摄像机跟随是一个非常重要的功能。一个流畅的摄像机跟随系统可以让玩家更好地沉浸在游戏世界中。本文将介绍如何在Unity中实现2D横版摄像机跟随&#xff0c;并分享一些优化技巧。 一、准备工作 在开始实现摄像机跟随之前&#xff0c;请确保您…

MFC 模态对话框的实现原理

参考自MFC 模态对话框的实现原理 - 西昆仑 - OSCHINA - 中文开源技术交流社区 1. 模态对话框 在涉及 GUI 程序开发的过程中&#xff0c;常常有模态对话框以及非模态对话框的概念 模态对话框&#xff1a;在模态对话框活动期间&#xff0c;父窗口是无法进行消息响应&#xff0…

JavaEE初阶多线程 (5)

1.锁的策略 1.1锁的策略是什么 这个锁的策略可以理解为&#xff0c;一种做法&#xff0c;相当于当你遇到锁竞争&#xff0c;加锁解锁&#xff0c;的情况你会怎么做。 乐观锁可以理解为疫情的时候比较乐观就买了最基本的物资&#xff0c; 买的时候非常方便 1.2乐观锁 当效率…

Wireshark抓包后的报文太大,如何拆分?

背景&#xff1a;抓包获取到一个400多兆的网络数据包.pcapng文件&#xff0c;使用wireshark软件可以正常打开。但需要把文件导出为.json文件&#xff0c;从而方便对报文内容做过滤分析。使用wireshark自带的导出功能导出后发现生成的.json文件大小为2G多&#xff0c;使用notepa…

Python实现定时任务的方式

大家好&#xff0c;在当今数字化的时代&#xff0c;定时任务的需求在各种应用场景中频繁出现。无论是数据的定时更新、周期性的任务执行&#xff0c;还是特定时间点的操作触发&#xff0c;Python 都为我们提供了强大而灵活的手段来实现这些定时任务。当我们深入探索 Python 的世…

【机器学习】AI大模型的探索—浅谈ChatGPT及其工作原理

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 &#x1f4da;介绍ChatGPT 1.1 什么是ChatGPT 1.2 ChatGPT的应用场景 &#x1f4a1;基础概念 1. 人工智能和机器学习 1.1 人工智能&#xff08;AI&#xff09;简介 1.2 机器学习&#xff08;ML&#xff09;简…