数据结构第七讲:栈和队列OJ题

news2024/11/15 12:11:42

数据结构第七讲:栈和队列OJ题

  • 1.有效的括号
  • 2.用队列实现栈
  • 3.用栈实现队列
  • 4.设计循环队列

1.有效的括号

链接: OJ题目链接
在这里插入图片描述

typedef char StackDataType;

typedef struct Stack
{
	StackDataType* arr;//使用一个指针来指向开辟的数组
	int capacity;//保存数组的空间大小
	int top;//指向栈顶
}Stack;

//栈的初始化
void Init(Stack* ps)
{
	assert(ps);

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

//栈的销毁
void Destory(Stack* ps)
{
	assert(ps);

	//注意:这个要加上if进行判断,为了确保arr数组不是指向NULL
	if(ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

//栈的插入
void StackPush(Stack* ps, StackDataType x)
{
	assert(ps);

	//因为只有栈的插入才需要开辟空间,所以开辟结点空间不必封装成一个函数
	if (ps->top == ps->capacity)
	{
		//空间不足,需要开辟
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		StackDataType* parr = (StackDataType*)realloc(ps->arr, newcapacity * sizeof(StackDataType));
		if (parr == NULL)
		{
			perror("malloc faile!");
			exit(1);
		}
		ps->arr = parr;
		ps->capacity = newcapacity;
	}
	ps->arr[ps->top++] = x;
}

//栈的删除
void StackPop(Stack* ps)
{
	//栈为NULL时不能删除,栈中没有数据时不能删除
	assert(ps && ps->top);

	--ps->top;
}

//取栈顶元素
StackDataType StackPrint(Stack* ps)
{
	assert(ps && ps->top);

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

//获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

--------------------------------------------------------------------------
//下面才是实现思路
bool isValid(char* s) {
    Stack ps;
    //先对栈进行初始化
    Init(&ps);

    while(*s)
    {
        if(*s=='(' || *s=='{' || *s=='[')
        {
            //三种情况,进行插入
            StackPush(&ps, *s);
        }
        else
        {
            if((ps.top == 0) || (ps.top==0 && *s!='\0')) return false;
            StackDataType a = StackPrint(&ps);
            if( (a=='(' && *s==')') ||  
                (a=='[' && *s==']') ||
                (a=='{' && *s=='}') );
            else
            {
                //不匹配时,直接返回false
                return false;
            }
        }
        s++;
    }
    if(ps.top!=0 && *s=='\0') return false;
    return true;
}

2.用队列实现栈

链接: OJ题目链接
在这里插入图片描述
在这里插入图片描述

//结点结构体
typedef int QueueDataType;

typedef struct QueueNode
{
	//和链表一样,也需要结点进行链接
	QueueDataType val;
	struct QueueNode* next;
}QueueNode;

//队列结构体
typedef struct Queue
{
	QueueNode* head;//指向队列的头部,方便删除数据
	QueueNode* tail;//指向队列的尾部,方便插入数据
	int size;//用来记录有效数据的个数
}Queue;

//队列初始化
void Init(Queue* pq)
{
	assert(pq);

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//销毁队列
void Destory(Queue* pq)
{
	assert(pq);

	QueueNode* prev = pq->head;
	while (prev)
	{   
        QueueNode* next = prev->next;
		free(prev);
		prev = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//入队列
void QueuePush(Queue* pq, QueueDataType x)
{
	assert(pq);

	//只有入队列需要开辟结点空间
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc faile!");
		exit(1);
	}
	newnode->val = x;
	newnode->next = NULL;
	//要分情况讨论:当队列一开始没有一个结点时
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		//直接插入到末尾即可
		//head ... tail newnode
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

//出队列
void QueuePop(Queue* pq)
{
	assert(pq && pq->head);

	//出队列要求从队列开头进行删除
	//此时要分情况讨论:当只具有一个结点时
	if (pq->head == pq->tail)
	{
		free(pq->head);
		pq->head = pq->tail == NULL;
	}
	else
	{
		//pq->head pq->head->next
		QueueNode* tmp = pq->head->next;
		free(pq->head);
		pq->head = tmp;
	}
	--pq->size;
}

//取队列头结点数据
QueueDataType QueueFront(Queue* pq)
{
	assert(pq && pq->head);

	return pq->head->val;
}

//取队列尾节点数据
QueueDataType QueueBack(Queue* pq)
{
	assert(pq && pq->head && pq->tail);

	return pq->tail->val;
}

//队列有效元素的个数
int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

//检查队列是否为空
bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head == NULL;
}
///
typedef struct {
    //需要创建两个队列
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    Init(&pst->q1);
    Init(&pst->q2);

    return pst;
}

void myStackPush(MyStack* obj, int x) {
    //将数据压入栈,首先要找到那个不为空的队列
    //假设第一个队列不为空
    Queue* none = &obj->q1;
    Queue* emp = &obj->q2;
    if(QueueEmpty(&obj->q1))
    {
        none = &obj->q2;
        emp = &obj->q1;
    }
    QueuePush(none, x);
}

int myStackPop(MyStack* obj) {
    //出栈
    Queue* none = &obj->q1;
    Queue* emp = &obj->q2;
    if(QueueEmpty(&obj->q1))
    {
        none = &obj->q2;
        emp = &obj->q1;
    }
    //先将size-1个数据保存到空的队列中
    while(QueueSize(none) > 1)
    {
        int data = QueueFront(none);
        QueuePush(emp, data);
        QueuePop(none);
    }
    int data = QueueFront(none);
    QueuePop(none);
    return data;
}

int myStackTop(MyStack* obj) {
    //取栈顶元素
    Queue* none = &obj->q1;
    Queue* emp = &obj->q2;
    if(QueueEmpty(&obj->q1))
    {
        none = &obj->q2;
        emp = &obj->q1;
    }
    return QueueBack(none);
}

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    Destory(&obj->q1);
    Destory(&obj->q2);
    free(obj);
    obj = NULL;
}

3.用栈实现队列

链接: OJ题目链接
在这里插入图片描述
在这里插入图片描述

typedef int StackDataType;

typedef struct Stack
{
	StackDataType* arr;//使用一个指针来指向开辟的数组
	int capacity;//保存数组的空间大小
	int top;//指向栈顶
}Stack;

//栈的初始化
void Init(Stack* ps)
{
	assert(ps);

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

//栈的销毁
void Destory(Stack* ps)
{
	assert(ps);

	//注意:这个要加上if进行判断,为了确保arr数组不是指向NULL
	if(ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

//栈的插入
void StackPush(Stack* ps, StackDataType x)
{
	assert(ps);

	//因为只有栈的插入才需要开辟空间,所以开辟结点空间不必封装成一个函数
	if (ps->top == ps->capacity)
	{
		//空间不足,需要开辟
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		StackDataType* parr = (StackDataType*)realloc(ps->arr, newcapacity * sizeof(StackDataType));
		if (parr == NULL)
		{
			perror("malloc faile!");
			exit(1);
		}
		ps->arr = parr;
		ps->capacity = newcapacity;
	}
	ps->arr[ps->top++] = x;
}

//栈的删除
void StackPop(Stack* ps)
{
	//栈为NULL时不能删除,栈中没有数据时不能删除
	assert(ps && ps->top);

	--ps->top;
}

//取栈顶元素
StackDataType StackPrint(Stack* ps)
{
	assert(ps && ps->top);

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

//获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

//检查栈是否为空
bool StackCheck(Stack* ps)
{
    assert(ps);

    return ps->top == 0;
}
/
typedef struct {
    //首先要创建出两个栈结构体
    Stack push;
    Stack pop;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));

    Init(&queue->push);
    Init(&queue->pop);

    return queue;
}

void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->push, x);
}

int myQueuePop(MyQueue* obj) {
    //删除元素要在pop队列中删除
    //此时要进行讨论
    //当pop链表还不为空时,直接删除一个元素即可
    if(!StackCheck(&obj->pop))
    {
        int data = StackPrint(&obj->pop);
        StackPop(&obj->pop);
        return data;
    }
    //当pop链表为空时,需要将push链表中的数据移到pop链表中
    //先将元素全部移到pop队列中
    while(!StackCheck(&obj->push))
    {
        int data = StackPrint(&obj->push);
        StackPush(&obj->pop, data);
        StackPop(&obj->push);
    }
    //然后删除pop中的一个元素即可
    int data = StackPrint(&obj->pop);
    StackPop(&obj->pop);
    return data;
}

int myQueuePeek(MyQueue* obj) {
    //返回队列开头的元素
    //此时也要进行检查
    if(!StackCheck(&obj->pop))
    {
        return StackPrint(&obj->pop);
    }
    //当pop链表为空时,需要将push链表中的数据移到pop链表中
    //先将元素全部移到pop队列中
    while(!StackCheck(&obj->push))
    {
        int data = StackPrint(&obj->push);
        StackPush(&obj->pop, data);
        StackPop(&obj->push);
    }
    return StackPrint(&obj->pop);
}

bool myQueueEmpty(MyQueue* obj) {
    //检查队列是否为空
    return StackCheck(&obj->push) && StackCheck(&obj->pop);
}

void myQueueFree(MyQueue* obj) {
    Destory(&obj->push);
    Destory(&obj->pop);
    free(obj);
    obj = NULL;
}

4.设计循环队列

链接: OJ题目链接
要区分队列已满和队列中无数据就要多开辟一块空间,但是那一块空间只是一个指代作用,其实并不会被使用

在这里插入图片描述

在这里插入图片描述

typedef struct {
    int *arr;
    int front;
    int rear;
    int capacity;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* tmp = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //需要多创建一个int字节的空间,因为后边还要使用
    tmp->arr = (int*)malloc(sizeof(int) * (k+1));
    tmp->front = tmp->rear = 0;
    tmp->capacity = k;

    return tmp;
}

//判断循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear + 1) % (obj->capacity + 1) == obj->front;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //当队列已满时不能进行插入数据
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    //当循环队列不满时,在rear位置插入数据即可
    obj->arr[obj->rear++] = value;
    //如果rear的结果超出了数组的大小,要对rear的值进行一个更正
    obj->rear %= (obj->capacity+1);
    return true;
}

//判断队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->rear == obj->front;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //删除数据时直接移动front的指向即可
    //当队列为空时不能够执行删除操作
    if(myCircularQueueIsEmpty(obj));
    {
        return false;
    }
    obj->front++;
    //对front的位置进行校正
    obj->front %= (obj->capacity+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;
    }
    int prev = obj->rear - 1;
    if (obj->rear == 0)
    {
        prev = obj->capacity - 1;
    }
    return obj->arr[prev];
}

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

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

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

相关文章

concrt140.dll丢失是什么情况?有效的解决dll!

concrt140.dll文件丢失是电脑中少见的文件,但也会因为某些原因会导致电脑丢失concrt140.dll文件,那么出现这文件的原因是什么呢?出现这样的问题有什么办法可以将concrt140.dll修复呢?一起来看看吧。 为什么会缺失concrt140.dll文件…

前端:数字世界的门面与灵魂

在当今数字化时代,前端作为用户与网站或应用直接交互的界面,其重要性不言而喻。它不仅是信息的展示窗口,更是用户体验(UX)和用户界面(UI)设计的核心。本文将深入剖析前端在整体网站或应用中的重…

vscode 创建QT最简工程

1. 前提条件 qt 安装cmake安装 参考: https://blog.csdn.net/qq_51355375/article/details/139890889vscode 环境配置 参考: https://blog.csdn.net/qq_51355375/article/details/140733495 2. 工程创建 include 放头文件src .cpp 文件CMakeList.tex …

物品租赁小程序论文(设计)开题报告

一、课题的背景和意义 近些年来,随着移动互联网巅峰时期的来临,互联网产业逐渐趋于“小、轻、微”的方向发展,符合轻应用时代特点的各类技术受到了不同领域的广泛关注。在诸多产品中,被誉为“运行着程序的网站”之名的微信小程序…

搭建开发环境

1、安装VMware 参考01【正点原子】ATK-DLRK3568嵌入式Linux系统开发手册V1.2 2、安装ubuntu 参考01【正点原子】ATK-DLRK3568嵌入式Linux系统开发手册V1.2 2.1、Ubuntu 系统设置 root 用户密码 新安装的ubuntu没有设置 root 用户密码,打开终端,输入 sudo passwd root 执…

C#使用NModbus4库创建Modbus TCP Slave(服务器)简单示例

本文续上篇Codesys—标准库ModbusTCP Master(客户端)配合C#的NModbus4库的通讯示例 链接:https://blog.csdn.net/wushangwei2019/article/details/136375234?spm1001.2014.3001.5501 上篇描述在Codesys端的Modbus TCP Master(客户端)的设备添加、IO映射、通讯简单…

机器视觉12-相机

相机 作用: 工业相机 是 机器视觉系统 的重要组成部分 最本质的功能就是通过CCD或CMOS成 像传感器将镜头产生的光信号转变为 有序的电信号,并将这些信息通过相 应接口传送到计算机主机 工业相机分类 目前业内没有对相机进行明确的分类定义, 以下分类是…

svn软件总成全内容

SVN软件总成 概述:本文为经验型文档 目录 D:\安装包\svn软件总成 的目录D:\安装包\svn软件总成\svn-base添加 的目录D:\安装包\svn软件总成\tools 的目录D:\安装包\svn软件总成\tools\sqlite-tools-win32-x86-3360000 的目录D:\安装包\svn软件总成\安装包-----bt lo…

一分钟搞定文件翻译|2024年4款翻译工具,职场达人都在用!

在全球化的大环境下,跨国沟通和协作变得非常普遍。不管是在公司间谈生意,还是跟外国朋友聊天,翻译文件成了我们经常要做的事情。但是一大堆文件和各种各样的语言,怎么才能又快又好地翻译出来,提升工作速度呢&#xff1…

本地部署Whisper Web结合内网穿透实现远程访问本地语音转文本模型

本地部署Whisper Web结合内网穿透实现远程访问本地语音转文本模型 🧑 博主简介:现任阿里巴巴嵌入式技术专家,15年工作经验,深耕嵌入式人工智能领域,精通嵌入式领域开发、技术管理、简历招聘面试。CSDN优质创作者&…

分享10个免费的职场办公常用工具网站

在现代职场中,高效办公工具网站的使用可以显著提升工作效率。小编今天就和大家分享10个免费实用且高质量的职场办公常用工具网站。 1.Convertio Convertio是一个万能文件转换工具,支持多种格式之间的转换,包括PDF、Excel、Word等。它操作简…

C#与欧姆龙PLC 通信——fins udp协议

前言 欧姆龙PLC在工控领域占有很大的市场份额,在上位机编程领域,实现上位机和欧姆龙PLC的通信也是必备的技能,上位机和PLC可以通过fins udp和fins tcp协议通信,本文介绍的是fins udp协议,该协议具有传输速度快的特点,为了帮助大家学习fins udp协议,我编写了“欧姆龙Fin…

【从0制作自己的ros导航小车:上、下位机通信篇】上、下位机串口DMA通信

从0制作自己的ros导航小车 前言一、准备工作二、下位机端(STM32)三、上位机端(旭日x3派)四、测试 前言 下位机的电机驱动、轮速读取、偏航角读取都已经完成,接下来就是上下位机的桥梁:串口通信。 使用USB转…

Mysql in 与 exists

在MySQL中,IN和EXISTS都是用于子查询的条件语句,但它们在性能和使用场景上有不同的特点和应用。下面是对它们的详细介绍以及示例说明:

springboot中小型酒店管理系统-计算机毕业设计源码02793

摘要 随着互联网和移动技术的快速发展,酒店行业也面临着巨大的变革和机遇。传统的酒店管理方式存在着信息不透明、预订流程繁琐等问题,无法满足现代消费者对便捷、高效、个性化服务的需求。因此,开发中小型酒店管理系统具有重要的意义。本文旨…

9000字干货:从消息流平台Serverless之路,看Serverless标准演进

本文分享自华为云社区《9000字干货:从消息流平台Serverless之路,看Serverless标准演进》 这是一个最美好的时代。 随着以数字化升级为代表的第四次工业革命浪潮的席卷,企业正在不断地深化运用这一技术,构建一个又一个全连接&…

module AttributeError: ‘matplotlib.cm has no attribute ‘register_cmap‘

使用seaborn或者matplotlib报错: module AttributeError: matplotlib.cm has no attribute register_cmap‘ 这个一般是matplotlib版本变化导致 register_cmap‘函数名称发生了改变,升高或者降低matplotlib版本版本即可。 实验后matplotlib 3.7.3 中不…

【漏洞复现】泛微E-Cology9 WorkPlanService 前台SQL注入

文章目录 0x00 漏洞描述影响范围 0x01 测绘工具0x02 漏洞复现0x03 Nuclei检测脚本0x04 修复建议0x05 免责声明 0x00 漏洞描述 泛微E-Cology9 是泛微网络科技股份有限公司开发的一款高效、灵活、全面的企业信息化办公系统。 泛微E-Cology9 中的 /services/WorkPlanService 接口…

docker一些常用的命令

查看当前正在运行的容器&#xff0c;使用docker ps命令&#xff0c;使用这个命令可以展示出容器列表&#xff0c;记住其中需要的容器id。 docker ps 使用docker exec命令进入容器。该命令的基本语法是&#xff1a;docker exec [选项] <容器名称或ID> <要执行的命令&…

Flink笔记整理(四)

Flink笔记整理&#xff08;四&#xff09; 文章目录 Flink笔记整理&#xff08;四&#xff09;六、Flink中的时间和窗口6.1 窗口&#xff08;Window&#xff09;窗口的概念窗口的分类窗口API概览窗口分配器窗口函数&#xff08;Window Functions&#xff09; 6.2 时间语义&…