数据结构——栈与队列的专题

news2025/1/20 3:36:06

文章目录

  • 前言
  • 一、用队列实现栈
  • 二、用栈实现队列
  • 三、设计循环队列

前言

本篇是围绕栈与队列来展开,需要知道一定有关它们的相关基础知识

栈的详解
队列的详解

还有一道基础的栈题——有效的括号

一、用队列实现栈

原题链接:用队列实现栈

在这里插入图片描述

解题思路:
首先创建一个队列结构

然后用两个队列去实现一个栈,每次始终保持一个队列为空

入栈操作相当于给非空队列进行入队操作
出栈操作相当于非空队列的队尾元素出队,此时需要把非空队列除最后一个元素之外的其余元素入队到空队列,然后出队最后一个队尾元素

在这里插入图片描述

在这里插入图片描述

//实现队列
typedef int QDateType;
typedef struct QueueNode
{
	QDateType val;
	struct QueueNode* next;
}QNode;

//管理队列的结构体
typedef struct Queue
{
	QNode* phead;//指向队头的指针
	QNode* ptail;//指向队尾的指针
	int size;//队列数据个数
}Queue;

//队列的初始化
void QueueInit(Queue* pq);
//队列的销毁
void QueueDestroy(Queue* pq);

//队尾插入数据
void QueuePush(Queue* pq, QDateType x);
//队头删除数据
void QueuePop(Queue* pq);

//取出队尾的数据
QDateType QueueBack(Queue* pq);
//取出队头的数据
QDateType QueueFront(Queue* pq);

//取出队列数据个数
int QueueSize(Queue* pq);

//判断置空
bool QueueEmpty(Queue* pq);


//队列的初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	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;
}


//队尾插入数据
void QueuePush(Queue* pq, QDateType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;

	//没有结点时,头插
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	//有结点时,尾插
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

//队头删除数据
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	//只有一个结点
	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--;
}

//取出队尾的数据
QDateType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}

//取出队头的数据
QDateType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

//取出队列数据个数
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//判断置空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->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;
}

void myStackPush(MyStack* obj, int x)
{
    //将数据插入非空队列
    if(!QueueEmpty(&(obj->p1)))
    {
        QueuePush(&(obj->p1), x);
    }
    else
    {
        QueuePush(&(obj->p2), x);
    }
}

int myStackPop(MyStack* obj)
{
    //假设法
    Queue* empty = &(obj->p1);
    Queue* nonempty = &(obj->p2);
    if(!QueueEmpty(&(obj->p1)))
    {
       empty = &(obj->p2);
       nonempty = &(obj->p1);
    }
    //将size-1个数据移动到空队列
    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->p1)))
    {
        return QueueBack(&(obj->p1));
    }
    else
    {
        return QueueBack(&(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);
}

二、用栈实现队列

原题链接:用栈实现队列
在这里插入图片描述

解题思路:

此题可以用两个栈实现,一个栈进行入队操作,另一个栈进行出队操作

出队操作: 当出队的栈不为空时,直接进行出栈操作,如果为空,需要把入队的栈元素全部导入到出队的栈,然后再进行出栈操作

在这里插入图片描述

//实现动态增长的栈
typedef int STDateType;
typedef struct Stack
{
	STDateType* a;
	int top;//栈顶
	int capacity;//容量
}ST;

//初始化和销毁
void STInit(ST* pst);
void STDestroy(ST* pst);

//入栈和出栈
void STPush(ST* pst, STDateType x);
void STPop(ST* pst);

//取栈顶数据
STDateType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//获得数据的个数
int STSize(ST* pst);

//初始化和销毁
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	//top指向栈顶数据的下一个元素
	pst->top = 0;

	//top指向栈顶元素
	//pst->top = -1;

	pst->capacity = 0;
}

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

//入栈和出栈
void STPush(ST* pst, STDateType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		//扩容
		int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;
		STDateType* tmp = realloc(pst->a, newcapacity * sizeof(ST));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top++] = x;
}

void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}

//取栈顶数据
STDateType 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* pst = (MyQueue*)malloc(sizeof(MyQueue));
    //初始化栈
    STInit(&(pst->pushst));
    STInit(&(pst->popst));
    return pst;
}

void myQueuePush(MyQueue* obj, int x)
{
    //默认插入第一个栈
    STPush(&(obj->pushst),x);
}
int myQueuePeek(MyQueue* obj);
int myQueuePop(MyQueue* obj)
{
    //调用peek函数
    int top = myQueuePeek(obj);
    //删除栈顶元素
    STPop(&(obj->popst));
    return top;
}

int myQueuePeek(MyQueue* obj)
{
    //检查第二个栈是否为空
    if(STEmpty(&(obj->popst)))
    {
        //如果空,将第一个栈的数据移动过来
        while(!STEmpty(&(obj->pushst)))
        {
            STPush(&(obj->popst), STTop(&(obj->pushst)));
            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);
}

三、设计循环队列

原题链接:设计循环队列

在这里插入图片描述

解题思路:

通过一个定长数组实现循环队列

入队:首先要判断队列是否已满,再进行入队的操作,入队操作需要考虑索引循环的问题,当索引越界,需要让它变成最小值
出队:首先要判断队列是否为空,再进行出队操作,出队也需要考虑索引循环的问题

判空: 队头 = 队尾
判满: 队尾 + 1 = 队头


在这里插入图片描述

typedef struct
{
    int* a;//动态数组储存数据
    int head;//指向队头
    int tail;//指向队列尾数据的下一个位置
    int k;//队列长度    
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k)
{
    //开辟一个循环队列
    MyCircularQueue* pst = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //创建一个可以存放k个元素的循环队列,实际申请的空间为k + 1
    pst->a = (int*)malloc((k + 1) * sizeof(int));
    pst->head = 0;
    pst->tail = 0;
    pst->k = k;
    return pst;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
    return obj->head == obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj)
{
    return (obj->tail + 1) % (obj->k + 1) == obj->head;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    //注意回绕问题
    obj->a[obj->tail++] = value;
    obj->tail %= obj->k + 1;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    //注意回绕问题
    obj->head++;
    obj->head %= obj->k + 1;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->head];
}

int myCircularQueueRear(MyCircularQueue* obj)
{
     if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[(obj->tail - 1 + obj->k + 1 )% (obj->k + 1)];
}

void myCircularQueueFree(MyCircularQueue* obj)
{
    free(obj->a);
    free(obj);    
}

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

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

相关文章

YOLOv5‘YOLOv7涨点必备:改进无参注意力SimAM

论文题目:SimAM: A Simple, Parameter-Free Attention Module for Convolutional Neural Networks 论文地址:http://proceedings.mlr.press/v139/yang21o/yang21o.pdf 源代码:https://github.com/ZjjConan/Sim 1.摘要 本文提出一种概念简单且非常有效的注意力模块。不同于…

攻防世界-web-file_include

题目 解题 通过阅读php代码,我们明显的可以发现,这个一个文件包含的类型题 文件包含漏洞也是一种“注入型漏洞”,其本质就是输入一段用户能够控制的脚本或者代码,并让服务器端执行。 require(),找不到被包含的文件时…

算法提高之单词接龙

算法提高之单词接龙 核心思想&#xff1a;dfs 预处理每两个字符串之间最短的公共部分长度 求最短公共 最终字符串是最长 dfs所有开头字符串 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 25;int g[N][N…

6818Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…

nowcoder——回文结构

链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 我们来分析该题&#xff1a;我们首先要清楚什么是回文结构&#xff1f;其实就是对称结构。如果一个链表呈对称结构就说明该链表具有回文结构。 下面给上一些例子&#xff1a; 那我们怎么判断该链表是否属于回文结构呢&#xf…

基于springboot的代驾管理系统的设计与实现

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

漫谈ApplicationContext和BeanFactory的区别

各位大佬光临寒舍&#xff0c;希望各位能赏脸给个三连&#xff0c;谢谢各位大佬了&#xff01;&#xff01;&#xff01; 目录 1.背景介绍 2.细述ApplicationContext和BeanFactory 3.总结 1.背景介绍 当我们使用SpringBoot创建项目的时候会看到一串代码&#xff1a…

123.Android 简单的定位和语音识别 免费高德定位 免费语音识别 不需要接入SDK 不需要导入任何的离线包

//免费的定位 高德定位 不需要接入高德SDk也可进行高德定位&#xff1a; //免费的语音识别 不需要接入任何的SDK 也不需要导入任何的离线语音包&#xff1a; //CSDN 小妞得意 //具体代码实现 私聊 //---------------------------------------------------------------END…

Ubuntu 使用nginx部署agular项目

我的front-end是用的webpack&#xff0c;就直接执行的npm run build打包。 完成之后就可以\target\classes\static找到 &#xff0c;直接把整个static上传到需要部署的地方就可以了。 当然这个打包output路径也是angular.json配置好了的 sudo apt update sudo apt install n…

设计模式之开放封闭原则

文章目录 定义理解 小结 定义 开闭原则规定软件中的对象、类、模块和函数对扩展应该是开放的&#xff0c;但对于修改是封闭的。这意味着应该用抽象定义结构&#xff0c;用具体实现扩展细节&#xff0c;以此确保软件系统开发和维护过程的可靠性。 理解 怎么理解这个呢&#x…

51-48 CVPR 2024 | Vlogger: make your dream a vlog 自编剧制作视频博客

24年1月&#xff0c;上海交大、上海人工智能实验室、中科院联合发布Vlogger&#xff1a;make your dream a vlog。该论文主要工作是生成超过5分钟的视频博客vlog。鉴于现有文本到视频T2V生成方法很难处理复杂的故事情节和多样化的场景&#xff0c;本文提出了一个名为Vlogger的通…

Photoshop 2022 for Mac/win:释放创意,打造专业级的图像编辑体验

在数字图像编辑的世界里&#xff0c;Adobe Photoshop 2022无疑是那颗璀璨的明星。这款专为Mac和Windows用户设计的图像处理软件&#xff0c;以其卓越的性能和丰富的功能&#xff0c;赢得了全球数百万创作者的青睐。 Photoshop 2022在继承前代版本强大功能的基础上&#xff0c;…

Unity图文混排EmojiText的使用方式和注意事项

​​​​​​​ 效果演示&#xff1a; 使用方式&#xff1a; 1、导入表情 2、设置图片格式 3、生成表情图集 4、创建/修改目标材质球 5、测试 修复换行问题 修复前&#xff1a; 修复后&#xff1a; 修复代码&#xff1a; 组件扩展 1、右键扩展 2、组件归类&#…

力扣题目:机器人能否返回原点

力扣题目&#xff1a;机器人能否返回原点 题目链接: 657.机器人能否返回原点 题目描述 代码思路 题目思路很简单&#xff0c;只要L数量等于R&#xff0c;U的数量等于D。 代码纯享版 class Solution {public boolean judgeCircle(String moves) {int LR 0, UD 0;for(int …

贝叶斯分类器详解

1 概率论知识 1.1 先验概率 先验概率是基于背景常识或者历史数据的统计得出的预判概率&#xff0c;一般只包含一个变量&#xff0c;例如P(A)&#xff0c;P(B)。 1.2 联合概率 联合概率指的是事件同时发生的概率&#xff0c;例如现在A,B两个事件同时发生的概率&#xff0c;记…

next水和错误

产生原因 应该是和预渲染有关&#xff0c;官方也有谈到 水和错误主要原因 这个主要事服务器端渲染和客户端渲染结果不一致&#xff0c;客户端再渲染导致的错误&#xff0c;主要结果就是耗费性能&#xff0c;当然也可以关闭提示错误 具体解决措施可以看看官方文档参考 相关的…

Vagrant + docker搭建Jenkins 部署环境

有人问&#xff0c;为什么要用Jenkins&#xff1f;我说下我以前开发的痛点&#xff0c;在一些中小型企业&#xff0c;每次开发一个项目完成后&#xff0c;需要打包部署&#xff0c;可能没有专门的运维人员&#xff0c;只能开发人员去把项目打成一个war包&#xff0c;可能这个项…

2024年5月10日有感复盘

2024年5月10日有感复盘 时间 今天是一个很美好的一天&#xff0c;原因是很平凡&#xff0c;读书很平凡&#xff0c;玩游戏很平凡&#xff0c;然后生活很平凡&#xff0c;未来可期&#xff0c;听歌很舒服&#xff0c;很喜欢一个人呆在图书馆的感觉&#xff0c;很喜欢发呆&…

VLM与基础分割模型的联合使用

最近做的项目里有涉及大模型&#xff0c;里面有一部分的功能是&#xff1a; 将图片输入VLM(视觉语言模型&#xff0c;我使用的是llava)&#xff0c;询问图中最显著的物体&#xff0c;将其给出的答案作为基础分割模型&#xff08;我使用的是Grounded-SAM&#xff09;的text prom…