【数据结构】栈和队列经典题目

目录

 

1.有效的括号【链接】

代码实现

2.用队列实现栈【链接】

代码实现 

3.用栈实现队列

​编辑

代码实现

4.循环队列(数组实现)【链接】

代码实现


1.有效的括号【链接】

题目描述:

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

思路:

栈后进先出的特点与本题括号排序特点一致,如果遇到左括号就入栈,一旦遇到右括号,就去找与它最近的左括号匹配(即找栈顶元素),如果匹配,弹出栈顶元素,去找下一个,如果不匹配,返回false。

例如:( ) { [ } ]   

' ( '入栈,++s, 遇到 ')' , 与栈顶元素' ( ' 相匹配,把' ( '弹出栈,++s,遇到 ' { '入栈,++s, 遇到 ' [ '入栈 ,++s,遇到 ' } ' , 与栈顶元素 ' [ ' 进行匹配,不配对,返回false,字符串无效。

代码实现

typedef char SLDataType;
typedef struct Stack 
{SLDataType* a;int top;int capacity;
} ST;// 初始化
void STInit(ST* pst)
{assert(pst);pst->a = NULL;// top指向栈顶数据的下一个位置pst->top = 0;pst->capacity = 0;
}// 销毁栈
void STDestroy(ST* pst) 
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}// 入栈
void STPush(ST* pst, SLDataType x) 
{assert(pst);// 扩容if (pst->top == pst->capacity) {int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;SLDataType* tmp =(SLDataType*)realloc(pst->a, newcapacity * sizeof(SLDataType));if (tmp == NULL) {perror("realloc fail");return;}pst->a = tmp;pst->capacity = newcapacity;}   pst->a[pst->top] = x;pst->top++;
}// 出栈
void STPop(ST* pst) 
{assert(pst);assert(pst->top > 0);pst->top--;
}// 获取栈顶数据
SLDataType 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;
}bool isValid(char* s) 
{ST st;STInit(&st);while (*s) {// 遇到左括号入栈if (*s == '(' || *s == '{' || *s == '[') {STPush(&st, *s);} else // 遇到右括号就取栈顶的左括号尝试进行匹配{//如果字符串就给了一个右括号,就无法取栈顶元素,所以要判断栈是否为空if(STEmpty(&st)){STDestroy(&st);return false;}char top = STTop(&st);//取栈顶元素STPop(&st); // 弹出栈顶元素// 判断不匹配if ((top == '(' && *s != ')') || (top == '{' && *s != '}') ||(top == '[' && *s != ']')) {STDestroy(&st);return false;}}++s;}//判空,如果栈为空,就都匹配了,栈不为空,说明还有没匹配的左括号,数量不匹配bool ret=STEmpty(&st);STDestroy(&st);return ret;
}

2.用队列实现栈【链接】

题目描述:

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

思路: 

构造两个队列,空队列用来导数据,非空队列用来插入数据,达到后进先出的效果。

例如:如果想将栈顶元素5拿走,而队列只能在队头删除元素,只能把1拿走,就再构造一个空队列导数据,将非空队列中前size-1个元素导入导空队列中,这时非空队列就只剩一个队头元素5,把它返回,然后pop掉它,此时又变成空队列了。

代码实现 

typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}//队尾插入
void QueuePush(Queue* pq, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = pq->ptail= newnode;		 }else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}//队头删除
void QueuePop(Queue* pq)
{assert(pq);assert(pq->size != 0);	//一个节点if (pq->phead->next == NULL){free(pq->phead);pq->phead = pq->ptail = NULL;}else//多个节点{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;		
}//取队头数据
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}//判空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}//销毁
void QueueDesTroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}//定义2个队列
typedef struct {  //匿名结构体Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() {MyStack*pst=(MyStack*)malloc(sizeof(MyStack));QueueInit(&(pst->q1));QueueInit(&(pst->q2));return pst;
}void myStackPush(MyStack* obj, int x) {if(!QueueEmpty(&(obj->q1))){QueuePush(&(obj->q1),x);}else{QueuePush(&(obj->q2),x);}}//移除并返回栈顶元素
int myStackPop(MyStack* obj) {//把不为空的队列的前size-1个数据导走到空队列并pop掉,剩下最后一个就是栈顶数据//假设法Queue*empty=&(obj->q1);Queue*nonempty=&(obj->q2);if(!QueueEmpty(&(obj->q1))){nonempty=&(obj->q1);empty=&(obj->q2);}while(QueueSize(nonempty)>1){QueuePush(empty,QueueFront(nonempty));QueuePop(nonempty);}int top=QueueFront(nonempty);QueuePop(nonempty);return top;
}//取栈顶元素
int myStackTop(MyStack* obj) {if(!QueueEmpty(&(obj->q1))){return QueueBack(&(obj->q1));//取队尾元素}else{return QueueBack(&(obj->q2));}
}//判空
bool myStackEmpty(MyStack* obj) {return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
}void myStackFree(MyStack* obj) {QueueDesTroy(&(obj->q1));//从里向外释放,先释放队列,再释放栈空间QueueDesTroy(&(obj->q2));free(obj);
}

3.用栈实现队列

题目描述:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路: 

将一个栈当作输入栈用来入数据,一个栈当作输出栈用来出数据,由于栈具有后进先出的特性,若输出栈为空,则将输入栈中的数据全部导入到输出栈,这样输出栈从栈顶到栈底的顺序就是队列的输出顺序。

代码实现

typedef int SLDataType;
typedef struct Stack
{SLDataType* a;//指向动态开辟的数组int top;//确定栈顶位置int capacity;//栈的容量
}ST;//初始化
void STInit(ST* pst)
{assert(pst);pst->a = NULL;//top指向栈顶数据的下一个位置pst->top = 0;	pst->capacity = 0;
}
//销毁栈
void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}//入栈
void STPush(ST* pst, SLDataType x)
{assert(pst);//扩容if (pst->top == pst->capacity){int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(pst->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail");return;}pst->a = tmp;pst->capacity = newcapacity;}//top指向栈顶数据的下一个位置pst->a[pst->top] = x;pst->top++;	
}
//出栈
void STPop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}//获取栈顶数据
SLDataType 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;
}//定义两个栈
typedef struct {ST pushst;ST popst;
} MyQueue;MyQueue* myQueueCreate() {MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));STInit(&(obj->pushst));STInit(&(obj->popst));return obj;
}void myQueuePush(MyQueue* obj, int x) {STPush(&(obj->pushst),x);    
}int myQueuePop(MyQueue* obj) {int front = myQueuePeek(obj);STPop(&(obj->popst));return front;
}//取poopst的栈顶元素
int myQueuePeek(MyQueue* obj) {if(STEmpty(&(obj->popst))){//导数据while(!STEmpty(&(obj->pushst))){int top=STTop(&(obj->pushst));STPush(&(obj->popst),top);STPop(&(obj->pushst));}}return STTop(&(obj->popst));
}bool myQueueEmpty(MyQueue* obj) {return STEmpty(&(obj->pushst)) && STEmpty(&(obj->popst));
}void myQueueFree(MyQueue* obj) {      STDestroy(&(obj->pushst));STDestroy(&(obj->popst));free(obj);
}

4.循环队列(数组实现)【链接】

代码实现

//循环队列结构
typedef struct {int* a;int front;//队头指针int rear;//队尾指针 指向尾的下一个元素int k;//队列长度
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多开一个空间obj->a = (int*)malloc(sizeof(int) * (k + 1));obj->front = 0;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;obj->a[obj->rear] = value;obj->rear++;obj->rear %= (obj->k + 1);//解决rear下标值回绕的问题return true;
}//出队
bool myCircularQueueDeQueue(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj))return false;obj->front++;obj->front %= (obj->k + 1);//解决front下标值回绕的问题return true;
}//获取队首元素
int myCircularQueueFront(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj))return -1;elsereturn obj->a[obj->front];
}//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj))return -1;elsereturn obj->rear == 0 ? obj->a[obj->k] : obj->a[obj->rear - 1];//与下面代码等价/*return obj->a[(obj->rear - 1 + obj->k + 1) % (obj->k + 1)];取模解决回绕问题*/       
}//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);
}

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

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

相关文章

Mycat 详细介绍及入门实战,解决数据库性能问题

一、基本原理 1、数据分片 (1)、水平分片 Mycat 将一个大表的数据按照一定的规则拆分成多个小表,分布在不同的数据库节点上。例如,可以根据某个字段的值进行哈希取模,将数据均匀的分布到不同的节点上。 这样做的好处…

数据结构7——二叉树的顺序结构以及堆的实现

在上篇文章数据结构6——树与二叉树中,我们了解了树和二叉树的概念,接着上篇文章,在本篇文章中我们学习二叉树顺序结构的实现。 目录 1. 二叉树的顺序存储结构 2. 堆的概念及结构 1. 堆的概念 2. 堆的结构 3. 堆的实现 1. 堆节点 2. 交…

R语言实现logistic回归曲线绘制

方式一&#xff1a;编制函数 x<-rnorm(10000)#设置随机种子 #编写绘图函数代码快 f <- function(x){y 1/(1 exp(-x))plot(x,y)}#sigmoid函数 f(x)​ 方式二&#xff1a;Sigmoid函数代码 x<-rnorm(10000)#设置随机种子 #编写绘图函数代码块 #y<-1/(1exp(-x)) y&…

数据结构-复杂度

复杂度 1.数据结构1.1算法 2.算法效率2.1复杂度的概念 3.时间复杂度3.1大O渐进表示法3.2时间复杂度计算示例3.2.1 示例13.2.2 示例23.2.3 示例33.2.4 示例43.2.5 示例5&#xff1a;3.2.6 示例63.2.7 示例7 4.空间复杂度4.1.1 示例14.1.2 示例2 5.常见复杂度对比6.复杂度算法题6…

【重学 MySQL】六十七、解锁检查约束,守护数据完整性

【重学 MySQL】六十七、解锁检查约束&#xff0c;守护数据完整性 检查约束的基本概念检查约束的语法检查约束的使用场景注意事项示例 在MySQL中&#xff0c;检查约束&#xff08;CHECK&#xff09;是一种用于确保表中数据满足特定条件的约束。 检查约束的基本概念 检查约束用…

考研前所学c语言02(2024/10/16)

1.一个十进制的数转化为二进制的就是不断除二取余&#xff0c;得到的余数从下到上取 比如123&#xff1a; 结果为&#xff1a; 同理其他的十进制转八进制&#xff0c;十六进制就除八&#xff0c;除十六即可 再比如123转十六进制&#xff1a; 因为余数是11&#xff0c;十六进…

【JavaEE初阶】深入理解网络编程—使用UDP协议API实现回显服务器

前言 &#x1f31f;&#x1f31f;本期讲解关于TCP/UDP协议的原理理解~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

从0开始深度学习(12)——多层感知机的逐步实现

依然以Fashion-MNIST图像分类数据集为例&#xff0c;手动实现多层感知机和激活函数的编写&#xff0c;大部分代码均在从0开始深度学习&#xff08;9&#xff09;——softmax回归的逐步实现中实现过 1 读取数据 import torch from torchvision import transforms import torchv…

查找与排序-交换排序

交换排序是基于“比较”和“交换”两种操作来实现的排序方法 。 由于选择“比较”的基准元素不同&#xff0c;可将交换排序分为以下两种&#xff1a; 冒泡排序快速排序 一、冒泡排序 1.冒泡排序基本思想 因为其实现与气泡从水中往上冒的过程类似而得名。 每一趟的…

基于SpringBoot+Vue+uniapp微信小程序的垃圾分类系统的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

Redux (八) 路由React-router、嵌套路由、路由传参、路由懒加载

文章目录 一、React-Router的基本使用1. 安装及基本使用(路由映射配置)2. 路由跳转Link与NavLink3. Navigate导航4. 处理路径不存在的情况 二、嵌套路由三、手动跳转 (类似编程式路由导航)1. 函数式组件2. 类组件实现手动跳转 四、路由传参1. 路径设置占位符(params)2. search传…

Java面试指南:Java基础介绍

这是《Java面试指南》系列的第1篇&#xff0c;本篇主要是介绍Java的一些基础内容&#xff1a; 1、Java语言的起源 2、Java EE、Java SE、Java ME介绍 3、Java语言的特点 4、Java和C的区别和联系&#xff1f; 5、面向对象和面向过程的比较 6、Java面向对象的三大特性&#xff1a…

leetcode30:串联所有单词的字串

给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 words ["ab","cd","ef"]&#xff0c; 那么 "abcdef…

1. 解读DLT698.45-2017通信规约--预连接响应

国家电网有限公司企业标准&#xff0c;面向对象的用电信息数据交换协议DLT698.45-2017 为提高用电信息采集系统的业务适应性、采集效率、安全性和数据溯源性&#xff0c;规范用电信息数据交换协议的通信架构、数据链路层、应用层、接口类与对象标识&#xff0c;制定本标准。 …

Linux系统:(Linux系统概述与安装)

硬件计算机硬件是指计算机系统中所有物理部件的总称。包括计算机主机、显示器、键盘、鼠标、内存、硬盘、处理器、主板等等。这些硬件部件是计算机系统运行的基础 不管是电脑系统(个人电脑、服务器等)、还是移动端操作系统(手机、平板等)。它的功能就是做为用户和硬件之间的桥梁…

前端求职简历-待补充

当然可以&#xff0c;针对大厂的前端岗位&#xff0c;一个吸引人的简历应该突出你的技术能力、项目经验、教育背景以及任何能体现你学习能力和团队协作能力的证明。以下是一个简历大纲示例&#xff0c;你可以根据自己的实际情况进行调整&#xff1a; 个人信息 姓名联系方式&a…

图文深入介绍oracle资源管理(续)

1. 引言&#xff1a; 本文将承接上篇继续深入介绍oracle资源管理。本文重点介绍如何使用oracle资源管理器管理好DB。 2. 资源管理器&#xff1a; 可以使用图形界面 OEM$或命令行调用 DBMS RESOURCE MANAGER 程序包的过程进行数据库资源管理。 调用资源管理器的先决条件&…

瑞数后缀加密怎么处理

前言&#xff1a; 瑞数我们经常补环境通过&#xff0c;但是遇到瑞数后缀不知道怎么处理 就拿瑞数4来讲 解决方法&#xff1a; &#xff08;1&#xff09;传明文加密参数 一般情况&#xff0c;我们传明文加密参数也能访问 &#xff08;2&#xff09;再补环境基础调用open …

基于stm32的4G模块点灯实验

led模块功能封装 #include "led.h" #include "sys.h"//初始化GPIO函数 void led_init(void) {GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin GPIO_PIN_8 | GPIO_PIN_9;gpio_inits…

排序算法 —— 直接插入排序

目录 1.直接插入排序的思想 2.直接插入排序的实现 实现分析 实现代码 3.直接插入排序的分析 时间复杂度分析 空间复杂度分析 稳定性 1.直接插入排序的思想 直接插入排序的思想就是把待排序的元素按其关键码值的大小依次插入到一个已经排好序的有序序列中&#xff0c…