用队列实现栈 用栈实现队列 设计循环队列

news2024/9/19 16:58:55

用队列实现栈 

思路

栈的特点:后进先出   

队列的特点:先进先出

 使用两个队列实现栈:

 

我们可以使用两个队列,一个队列为:空队列,一个队列为:非空队列

当我们要出队列时:

将 size - 1个数据移动到空队列中,再将最后一个数据出队列,如此往复就可以完成4 3 2 1的出队列顺序

代码(c语言): 

队列的各种功能:

typedef int QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{
	struct QListNode* _next;
	QDataType _data;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* _front;
	QNode* _rear;
	int size;
}Queue;
// 初始化队列 
void QueueInit(Queue* q) {
	assert(q);

	q->size = 0;
	q->_front = NULL;
	q->_rear = NULL;
}
// 队尾入队列 
void QueuePush(Queue* q, QDataType data) {
	assert(q);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("QueuePush()::malloc()");
		return;
	}

	newnode->_data = data;
	newnode->_next = NULL;
	
	//队列为NULL
	if (q->_front == NULL)
	{
		q->_front = q->_rear = newnode;
	}
	else
	{
		q->_rear->_next = newnode;
		q->_rear = q->_rear->_next;
	}

	q->size++;
}
// 队头出队列 
void QueuePop(Queue* q) {
	assert(q);
	assert(q->size != 0);

	//单个节点
	if (q->_front == q->_rear)
	{
		free(q->_front);
		q->_front = q->_rear = NULL;
	}
	//多个节点
	else
	{
		QNode* next = q->_front->_next;
		free(q->_front);
		q->_front = next;
	}

	q->size--;
}
// 获取队列头部元素 
QDataType QueueFront(Queue* q) {

	assert(q);
	assert(q->_front);//队头不能为NULL

	return q->_front->_data;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* q) {
	assert(q);
	assert(q->_rear);//队尾不能为NULL

	return q->_rear->_data;
}
// 获取队列中有效元素个数 
int QueueSize(Queue* q) {

	return q->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q) {
	assert(q);

	return q->size == 0;
}
// 销毁队列 
void QueueDestroy(Queue* q) {
	assert(q);

	QNode* cur = q->_front;
	while (cur)
	{
		QNode* next = cur->_next;
		free(cur);
		cur = next;
	}

	q->_front = q->_rear = NULL;
	q->size = 0;

}

具体实现:

//使用两个队列实现栈
typedef struct {

    Queue q1;
    Queue q2;

} MyStack;

//初始化栈
MyStack* myStackCreate() {
    //创建一个栈
    MyStack* newStk = (MyStack*)malloc(sizeof(MyStack));

    //初始化栈(即初始化两个队列)
    QueueInit(&(newStk->q1));
    QueueInit(&(newStk->q2));

    return newStk;
}

//入栈
void myStackPush(MyStack* obj, int x) {

    //假设法找不为NULL的队列
    Queue* noempty = &obj->q1;
    if(QueueSize(noempty) == 0)
    {
        noempty = &obj->q2;
    }

    //往不为NULL队列中插入
    QueuePush(noempty,x);
}

//出栈
int myStackPop(MyStack* obj) {

    //假设法判断NULL队列,非NULL队列
    Queue* empty = &obj->q1;
    Queue* noempty = &obj->q2;
    if(QueueSize(noempty) == 0)
    {
        noempty = &obj->q1;
        empty = &obj->q2;
    }

    //将size - 1个数据移动到NULL队列中
    while(QueueSize(noempty) > 1)
    {
        QueuePush(empty,QueueFront(noempty));
        QueuePop(noempty);
    }

    //出栈
    int pop = QueueBack(noempty);
    QueuePop(noempty);

    return pop;

}

//获取栈顶元素
int myStackTop(MyStack* obj) {

    Queue* noempty = &obj->q1;
    if(QueueSize(noempty) == 0)
    {
        noempty = &obj->q2;
    }

    //获取栈顶数据,也就是队尾的数据
    return QueueBack(noempty);

}

//判NULL
bool myStackEmpty(MyStack* obj) {

    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);

}

//销毁栈
void myStackFree(MyStack* obj) {

    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
    
}

用栈实现队列

思路

使用两个栈实现队列

固定两个栈,1. 存数据栈(pushst) 2. 出数据栈(popst)

当我们要出数据时,把存数据栈(pushst)导入到 出数据栈(popst)中,在对栈顶取数据,如此往复就可以实现 4 3 2 1 的出栈顺序

代码(c语言):

栈的各种功能:

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

// 初始化和销毁
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 = pst->capacity = 0;
}

// 入栈  出栈
void STPush(ST* pst, STDataType x)
{
	assert(pst);

	// 扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
		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--;
}

// 取栈顶数据
STDataType 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* new = (MyQueue*)malloc(sizeof(MyQueue));

    STInit(&new->pushst);
    STInit(&new->popst);

    return new;
}

//入队列
void myQueuePush(MyQueue* obj, int x) {
    
    STPush(&obj->pushst,x);//插入至数据栈(pushst)中

}

//查看队头元素
int myQueuePeek(MyQueue* obj) {

    //查看出数据栈(popst),中是否有数据,有则直接查看栈顶数据,没有就把存数据栈(pushst)导入到 出数据栈(popst)中
    if(STEmpty(&obj->popst))
    {
        //把pushst数据全部导入popst
        while(!STEmpty(&obj->pushst))
        {
            STPush(&obj->popst,STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }

    //返回出数据栈(popst)栈顶数据
    return STTop(&obj->popst);

}

//出队列
int myQueuePop(MyQueue* obj) {

    //它会帮我们导数据到popst中,popst栈顶的数据就是我们要删除的数据
    int pop = myQueuePeek(obj);

    STPop(&obj->popst);

    return pop;
}


//判空
bool myQueueEmpty(MyQueue* obj) {

    return STEmpty(&obj->pushst) && STEmpty(&obj->popst);//两个栈为NULL则队列为NULL

}

//销毁队列
void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->pushst);
    STDestroy(&obj->popst);
    free(obj);
}

设计循环队列

        

 思路

利用数组来创建循环队列

代码:

typedef struct {
    int* a;
    int head;
    int rear;//指向最后一个数据的下一个空间
    int k;
} MyCircularQueue;


//初始化循环队列
MyCircularQueue* myCircularQueueCreate(int k) {

    MyCircularQueue* new = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //多开一个空间,用来解决数据为满与空的矛盾问题,当然也可以在结构体多加个size解决

    new->a = (int*)malloc(sizeof(int) * (k + 1));
    new->head = 0;
    new->rear = 0;//尾数据的下一个位置
    new->k = k;

    return new;
}

//插入队列
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {

    //判断循环队列满没有,满则不能继续插入
    if((obj->rear + 1) % (obj->k + 1) == obj->head)//当尾数据指针 + 1 = 头指针时,队列满
    return false;

    obj->a[obj->rear] = value;
    obj->rear++;

    obj->rear %= obj->k + 1;//循环

    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {

    //判断队列是否为空,为空则不能继续删除
    if(obj->head == obj->rear)//当尾指针 = 头指针时,队列为空
    return false;

    obj->head++;
    obj->head %= obj->k + 1; //循环
    return true;
}

//返回队列头数据
int myCircularQueueFront(MyCircularQueue* obj) {
    if(obj->head == obj->rear)
    return -1;

    return obj->a[obj->head];
}

//返回队列尾数据,即找尾指针指向的上一个地方
int myCircularQueueRear(MyCircularQueue* obj) {
    if(obj->head == obj->rear)
    return -1;
    
    return obj->a[(obj->k + obj->rear) % (obj->k + 1)];//往前绕k-1去找rear之前的一个数据

}

//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    //空
    return obj->head == obj->rear;
}

//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {

    return (obj->rear + 1) % (obj->k + 1) == obj->head;

}

//销毁队列
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

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

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

相关文章

束测后台实操文档1-PVE、PBS

合肥先进光源束测系统后台基础架构初步设计报告 合肥先进光源束测系统后台搭建进展2024.4.29 关于后台基础架构,写了上面两篇文档,只是框架的印象,没涉及到具体的实操,后面针对具体的搭建慢慢的完善操作的细节,从今年…

灌装线在线粒子浮游菌监测系统安装调试

近日,北京中邦兴业成功完成了某企业灌装线多个点位的洁净环境在线粒子浮游菌监测系统的施工并完成了前期的调试工作。 【项目现场】 北京中邦兴业技术工程师根据客户现场实际情况,进行了粒子、浮游菌的点位布置,此系统能够实时监测生产线上的…

Docker安装MySQL的详细教程

1. 拉取MySQL镜像 拉取MySQL镜像。您可以指定版本号,例如5.7或8.0,如果不指定,默认会拉取最新稳定版。 docker pull mysql:5.7或者,使用最新版本: docker pull mysql:latest2. 运行MySQL容器 拉取镜像完成后&#…

本特利135813-01在PLC系统中的应用与功能分析

本特利135813-01在PLC系统中的应用与功能分析 一、引言 在工业自动化和机械设备监测领域,高精度、高可靠性的传感器对于确保设备的稳定运行和故障预防具有至关重要的作用。本特利(Bently Nevada)作为振动监测领域的佼佼者,其1358…

Pytorch深度学习实践笔记10(b站刘二大人)

🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:pytorch深度学习 🎀CSDN主页 发狂的小花 🌄人生秘诀:学习的本质就是极致重复! 《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibi…

基于SVm和随机森林算法模型的中国黄金价格预测分析与研究

摘要 本研究基于回归模型,运用支持向量机(SVM)、决策树和随机森林算法,对中国黄金价格进行预测分析。通过历史黄金价格数据的分析和特征工程,建立了相应的预测模型,并利用SVM、决策树和随机森林算法进行训…

装机必备——WinRAR安装教程

装机必备——WinRAR安装教程 软件下载 软件名称:WinRAR 软件语言:简体中文 软件大小:3.38M 系统要求:Windows7或更高, 32/64位操作系统 硬件要求:CPU2GHz ,RAM4G或更高 下载通道①迅雷云盘丨下…

2024甘肃省三支一扶报名流程详细图解

预计报名时间:2024年5月27日9:00至5月31日18:00 2024甘肃省三支一扶报名流程 登录甘肃人力人力资源考试中心,选择网上报名 进入账户登录,首次登录同学请先注册账号。 注册账号,认真填写,仔细核对信息。…

AJ-Report一次排错处理

山重水复疑无路,柳暗花明又一村...... 新项目需要选型开源的AJ-Report,计划再次基础上进行二开。 官网地址: AJ-Report: AJ-Report是一个完全开源,拖拽编辑的可视化设计工具。三步快速完成大屏:配置数据源---->写…

矩阵对角化在机器学习中的奥秘与应用

在机器学习的广阔领域中,矩阵对角化作为一种重要的数学工具,扮演着不可或缺的角色。从基础的线性代数理论到复杂的机器学习算法,矩阵对角化都在其中发挥着重要的作用。 矩阵对角化的概念与原理 矩阵对角化是矩阵理论中的一个基本概念&#x…

红队攻防渗透技术实战流程:红队目标上线之webshell工具魔改

红队攻防免杀实战 1. 红队目标上线-Webshell免杀-源码魔改1.2 Webshell-代码混淆&流量绕过&工具原理1.2 通过对冰蝎的数据包分析:1.2魔改冰蝎-JAR反编译打包构建1.2魔改冰蝎-防识别-打乱特征指纹1.2魔改冰蝎-防查杀-新增加密协议1. 红队目标上线-Webshell免杀-源码魔改…

[8] CUDA之向量点乘和矩阵乘法

CUDA之向量点乘和矩阵乘法 计算类似矩阵乘法的数学运算 1. 向量点乘 两个向量点乘运算定义如下: #真正的向量可能很长,两个向量里边可能有多个元素 (X1,Y1,Z1) * (Y1,Y2,Y3) X1Y1 X2Y2 X3Y3这种原始输入是两个数组而输出却缩减为一个(单一值)的运…

mysql高级篇学习(数据表的设计方法,索引优化)

使用docker 安装 mysql 安装 docker # yum 包更新到最新 yum update# 卸载旧的 docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine # 安装 gcc 环境 yum -y install…

【程序员如何送外卖】

嘿,咱程序员要在美团送外卖,那还真有一番说道呢。 先说说优势哈,咱程序员那逻辑思维可不是盖的,规划送餐路线什么的,简直小菜一碟。就像敲代码找最优解一样,能迅速算出怎么送最省时间最有效率。而且咱平时…

基于 Wireshark 分析 UDP 协议

一、UDP 协议 UDP(User Datagram Protocol,用户数据报协议)是一种无连接的传输层协议,常用于传输即时数据,如音频、视频和实时游戏数据等。 UDP 的特点如下: 1. 无连接性:UDP 不需要在发送数…

如何在Namecheap上购买域名

文章目录 如何在Namecheap上购买国外域名,话不多说直接上步骤↓1:注册Namecheap账号2:选购域名3:如何付款4:付款购买域名5:总结 如何在Namecheap上购买国外域名,话不多说直接上步骤↓ 原文链接…

通过键值对访问字典

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中,如果想将字典的内容输出也比较简单,可以直接使用print()函数。例如,要想打印dictionary字典&#xff…

10.SpringBoot 统一处理功能

文章目录 1.拦截器1.1在代码中的应用1.1.1定义拦截器1.1.2注册配置拦截器 1.2拦截器的作用1.3拦截器的实现 2.统一数据返回格式2.1 为什么需要统⼀数据返回格式?2.2 统⼀数据返回格式的实现 3.统一异常处理4.SpringBoot专业版创建项目无Java8版本怎么办?…

Java后端面经

1.可重复读,已提交读,这两个隔离级别表现的现象是什么,区别是什么样的? 可重复读:表示整个事务看到的事务和开启后的事务能看到的数据是一致的,既然数据是一致的,所以不存在不可重复读。而且不…

Word整理论文参考文献

1.安装Zotero软件 2.安装Zotero的Chrome网站插件,并将插件固定到浏览器 3.安装Word的Zotero插件 4.在DBLP网站https://dblp.org/search 搜索需要添加的参考文献->点击BibTex->点击网页右上角的Zotero符号(即第二步所指的符号)->至…