【LeetCode&数据结构】栈和队列的应用——用队列实现栈问题、用栈实现队列问题详解


🔥个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》《数据结构与算法》C语言刷题12天IO强训LeetCode代码强化刷题

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平



**前言:**牛客网和LeetCode的刷题都不可或缺,我们都要做一做,无论是参加竞赛还是笔试面试,至少能提升你的代码能力!洛谷的题目也可以去做一做。力扣的题目对提升代码能力很有帮助,需要有一点基础,几乎都是接口型的题目,关于接口型和IO型的区别我们在本专栏的第一篇【LeetCode】力扣题------轮转数组、消失的数字、数组串联中就介绍过了,这里不再赘述,我们进入今天的力扣题目介绍------


目录

正文

一、用队列实现栈问题

(一)思路

(二)解题过程

1、初始化

2、入栈

3、出栈

4、取栈顶元素

5、判断栈是否为空

6、销毁栈

(三)完整代码

二、用栈实现队列问题

(一)思路

(二)解题过程

1、初始化

2、入队列

3、出队列

4、取队头

5、判断为空

6、销毁

(三)完整代码

结尾


正文

一、用队列实现栈问题

225.用队列实现栈

博主题解链接:调用队列结构实现栈

题目描述:

题目示例和提示------

(一)思路

我们的思路是:入栈:往不为空的队列中插入数据;出栈:把不为空队列中前size-1个数据挪到另一个队列,再将最后一个数据出队列;取栈顶(不出数据):找不为空的队尾数据,返回队尾数据(我们之前实现过取队尾操作)。如下图------

(二)解题过程

既然是用队列实现栈问题,那我们直接调用队列。

1、初始化

前面已经调用了队列的头文件和各种方法,我们就不用自己写了。

cpp 复制代码
//创建一个栈
MyStack* myStackCreate()
{
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&pst->q1);//把q1的地址传过去
    QueueInit(&pst->q2);

    return pst;
}
2、入栈

入栈的代码------

cpp 复制代码
//往栈里面插入一个栈顶元素
void myStackPush(MyStack* obj, int x) 
{
    //往不为空的队列里面插入数据
    if!(QueueEmpty(&obj->q1))//传q1的地址
    {
        //q1
        QueuePush(&obj->q1,x);
    }
    else{
        //q2
        QueuePush(&obj->q2,x);
    }
}
3、出栈
cpp 复制代码
    //不为空队列前size-1个数据挪到空队列中
    while(QueueSize(&noneEmp) > 1)
    {
        //取队头
        int front = QueueFront(&noneEmp);
        //入另一个队列
        QueuePush(&emp,front);
        //出队头
        QueuePop(&noneEmp)
    }

这里可以合并一下,反正返回值要作为第二个方法的front,那这里我们其实可以不创建临时变量,我们直接让返回值作为第二个参数------先取队头,再入到另一个队列当中------

cpp 复制代码
//取队头,入另一个队列
QueuePush(&emp,QueueFront(&noneEmp));
//出队头
QueuePop(&noneEmp)

出栈的代码------

cpp 复制代码
//往栈里面删除一个栈顶元素
int myStackPop(MyStack* obj) 
{
    //找不为空队列
    //类似于前面假设长短链表的方法,这里假设空和非空
    Queue* emp = &obj->q1;
    Queue* noneEmp = &obj->q2;
    if(QueueEmpty(&obj->q2))//这里是不加!的
    {
        emp = &obj->q2;
        noneEmp = &obj->q1;
    }
    //不为空队列前size-1个数据挪到空队列中
    while(QueueSize(&noneEmp) > 1)
    {
        //取队头,入另一个队列
        QueuePush(&emp,QueueFront(&noneEmp));
        //出队头
        QueuePop(&noneEmp)
    }
    //不为空队列数据出队
    int top = QueueFront(&noneEmp);
    QueuePop(&noneEmp);
    return top;
}

返回top值------

4、取栈顶元素
cpp 复制代码
//取栈顶元素
int myStackTop(MyStack* obj) 
{
    //找不为空队列,返回不为空队列的队尾数据
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else{
        return QueueBack(&obj->q2);
    }
}
5、判断栈是否为空
cpp 复制代码
//判断栈是否为空
bool myStackEmpty(MyStack* obj) 
{
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
6、销毁栈
cpp 复制代码
//销毁栈
void myStackFree(MyStack* obj) 
{
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
    obj = NULL;
}

(三)完整代码

cpp 复制代码
typedef int QDataType;
//定义节点的结构
 typedef struct QueueNode 
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;

 //定义队列的结构
typedef struct Queue 
{
	QueueNode* phead;//指向队头节点的指针
	QueueNode* ptail;//指向队尾节点的指针
	int size;		   //队列中有效数据个数
}Queue;

//初始化
void QueueInit(Queue* pq);

//销毁
void QueueDestory(Queue* pq);

//入队列,队尾
void QueuePush(Queue* pq, QDataType x);

// 出队列,队头
void QueuePop(Queue* pq);

//队列判空
bool QueueEmpty(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);

//取队尾数据
QDataType QueueBack(Queue* pq);

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

//初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

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

	QueueNode* pcur = pq->phead;
	while(pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;//防止phead、ptail变野指针
	pq->size = 0;//销毁后元素个数重置为0
}

//入队列,队尾
void QueuePush(Queue* pq, QDataType x)
{
	int size = 0;
	assert(pq);
	//创建值为x的节点
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	//队列为空
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;
	}
	pq->size++;//入队后元素个数+1
}

//队列判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL;
}

// 出队列,队头
void QueuePop(Queue* pq)
{
	assert(!QueueEmpty(pq));

	//队列中只有一个节点
	if (pq->phead == pq->ptail)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else 
	{
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;//出队后元素个数-1
}

//取队头数据
QDataType QueueFront(Queue* pq)
{ 
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

//队列有效元素个数
int QueueSize(Queue* pq)
{
	/*assert(pq);
	QueueNode* pcur = pq->phead;
	int size = 0;
	while (pcur)
	{
		++size;
		pcur = pcur->next;
	}
	return size;*/
	return pq->size;
}
//--------------------以上是队列的结构和常用方法----------------------

//两个队列实现一个栈
typedef struct
{
    Queue q1;
    Queue q2;
} MyStack;

//创建一个栈
MyStack* myStackCreate()
{
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&pst->q1);//把q1的地址传过去
    QueueInit(&pst->q2);

    return pst;
}
//往栈里面插入一个栈顶元素
void myStackPush(MyStack* obj, int x) {
    //往不为空的队列里面插入数据
    if(!QueueEmpty(&obj->q1))//传q1的地址
    {
        //q1
        QueuePush(&obj->q1, x);
    }
    else {
        //q2
        QueuePush(&obj->q2, x);
    }
}
//往栈里面删除一个栈顶元素
int myStackPop(MyStack* obj) {
    //找不为空队列
    //类似于前面假设长短链表的方法,这里假设空和非空
    Queue* emp = &obj->q1;
    Queue* noneEmp = &obj->q2;
    if (QueueEmpty(&obj->q2))//这里是不加!的
    {
        emp = &obj->q2;
        noneEmp = &obj->q1;
    }
    //不为空队列前size-1个数据挪到空队列中
    while (QueueSize(noneEmp) > 1)//这里不用取地址,本身就已经是地址了
    {
        //取队头,入另一个队列
        QueuePush(emp, QueueFront(noneEmp));
        //出队头
        QueuePop(noneEmp);
    }
    //不为空队列数据出队
    int top = QueueFront(noneEmp);
    QueuePop(noneEmp);
    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) {
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
    obj = NULL;
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);

 * int param_2 = myStackPop(obj);

 * int param_3 = myStackTop(obj);

 * bool param_4 = myStackEmpty(obj);

 * myStackFree(obj);
*/

二、用栈实现队列问题

232.用栈实现队列

博主题解链接:三步走方法用栈实现队列

题目描述:

题目示例和提示------

(一)思路

题目分析:

我们先画一下看看------

思路1:

思路2:

因此,我们的思路还是三步走:

(二)解题过程

1、初始化
cpp 复制代码
//初始化
MyQueue* myQueueCreate() 
{
    MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
    //栈的初始化
    STInit(&pq->pushST);//STInit的形参是一个一级指针,要传地址
    STInit(&pq->popST);

    return pq;
}
2、入队列
cpp 复制代码
//入队列
void myQueuePush(MyQueue* obj, int x) 
{
    //往pushST中插入数据
    STPush(&obj->pushST);
}
3、出队列

刚才我们分析过了,出队列要判断popST为不为空****------

cpp 复制代码
//出队列------要判断popST为不为空
int myQueuePop(MyQueue* obj) 
{
    //popST为空------将pushST(不为空)导入到popST
    if(STEmpty(&obj->popST)
    {
        while(!STEmpty(&obj->pushST))
        {
            //取栈顶(pushST),入popST栈,出pushST栈
            STPush(&obj->popST,STTop(&obj->pushST));
            STPop(&obj->pushST);
        }
    }
    //popST不为空直接出
    int top = STTop(&obj->popST);
    STPop(&obj->popST);
    return top;
}
4、取队头

取队头其实和出队列几乎一样,只不过取队头不用删除数据****------

cpp 复制代码
//取队头
int myQueuePeek(MyQueue* obj) 
{
   //popST为空------将pushST(不为空)导入到popST
    if(STEmpty(&obj->popST))
    {
        while(!STEmpty(&obj->pushST))
        {
            //取栈顶(pushST),入popST栈
            STPush(&obj->popST,STTop(&obj->pushST));
            STPop(&obj->pushST);
        }
    }
    //popST不为空直接取数据
    int top = STTop(&obj->popST);
    return top;
}
5、判断为空

两个栈为空,才能为空------

cpp 复制代码
//判断是否为空
bool myQueueEmpty(MyQueue* obj) 
{
    return STEmpty(&obj->popST) && STEmpty(&obj->pushST);
}
6、销毁

对队列进行销毁操作:

1、初始化那儿有个指向队列的指针是malloc出来的,得销毁;

2、在队列里面有两个栈也是向操作空间malloc出来的,也要销毁。

cpp 复制代码
void myQueueFree(MyQueue* obj) 
{
    STDestory(&obj->pushST);
    STDestory(&obj->popST);
    free(obj);
    obj = NULL;
}

(三)完整代码

cpp 复制代码
typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top;//定义栈中有效的数据个数
	int capacity;//栈的空间大小
}ST;

//初始化
void STInit(ST* ps)
{
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

//销毁
void STDestory(ST* ps)
{
	if (ps->arr)
		free(ps->arr);

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

//入栈------栈顶
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	//判断空间是否足够
	if (ps->top == ps->capacity)
	{
		//增容
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}

//栈是否为空
bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

//出栈------栈顶
void STPop(ST* ps)
{
	assert(!STEmpty(ps));
	ps->top--;
}

//取栈顶元素
STDataType STTop(ST* ps)
{
	assert(!STEmpty(ps));
	return ps->arr[ps->top - 1];
}

//获取栈中有效元素个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}
//-----------------以上栈的结构定义和常见的方法----------------------
typedef struct {
    ST pushST;
    ST popST;
} MyQueue;

//初始化
MyQueue* myQueueCreate() {
    MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
    //栈的初始化
    STInit(&pq->pushST);//STInit的形参是一个一级指针,要传地址
    STInit(&pq->popST);

    return pq;
}
//入队列
void myQueuePush(MyQueue* obj, int x) {
    //往pushST中插入数据
    STPush(&obj->pushST,x);
}
//出队列------要判断popST为不为空
int myQueuePop(MyQueue* obj) {
    //popST为空------将pushST(不为空)导入到popST
    if(STEmpty(&obj->popST))
    {
        while(!STEmpty(&obj->pushST))
        {
            //取栈顶(pushST),入popST栈,出pushST栈
            STPush(&obj->popST,STTop(&obj->pushST));
            STPop(&obj->pushST);
        }
    }
    //popST不为空直接出
    int top = STTop(&obj->popST);
    STPop(&obj->popST);
    return top;
}
//取队头
int myQueuePeek(MyQueue* obj) {
   //popST为空------将pushST(不为空)导入到popST
    if(STEmpty(&obj->popST))
    {
        while(!STEmpty(&obj->pushST))
        {
            //取栈顶(pushST),入popST栈
            STPush(&obj->popST,STTop(&obj->pushST));
            STPop(&obj->pushST);
        }
    }
    //popST不为空直接取数据
    int top = STTop(&obj->popST);
    return top;
}
//判断为空
bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->popST) && STEmpty(&obj->pushST);
}
//对队列进行销毁操作
//1.初始化那儿有个指向队列的指针是malloc出来的,得销毁
//2.在队列里面有两个栈也是向操作空间malloc出来的,也要销毁
void myQueueFree(MyQueue* obj) {
    STDestory(&obj->pushST);
    STDestory(&obj->popST);
    free(obj);
    obj = NULL;
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/

结尾

往期回顾:

【LeetCode&数据结构】栈的应用------有效的括号问题详解

由于本专栏的篇数越来越多,为了避免文章链接挂太多影响观感,博主之后的每一篇力扣刷题详解都只会附上前一篇的链接,最后一次完整链接是在之后会发布的【栈的应用------有效的括号问题详解】和【单链表的应用------环形链表问题详解】的文章结尾,本意是为了方便大家找到相应的详细的题解,现在文章多了,铸币博主没办法一一罗列,而且还会有"凑字数"的嫌疑,力扣刷题专栏的链接每次都会放在文章开头的位置,大家可自行前往!

感谢大家的理解与支持!

【LeetCode&数据结构】单链表的应用------环形链表问题详解

**结语:**本篇文章到这里就结束了,本文讲述的两道代码题并不适合C语言初学者,需要有一定的C语言基础,最好要学过数据结构与算法的算法复杂度和链表的知识,才能写出复杂度较优的代码来。大家一定要自己动手敲一敲,不敲的话不仅容易忘记,也不方便将来复习。

相关推荐
吃饭只吃七分饱3 分钟前
C++第8章:IO库
开发语言·c++
闪电麦坤954 分钟前
数据结构:字符串(Strings)
数据结构
宴之敖者、29 分钟前
数组——初识数据结构
c语言·开发语言·数据结构·算法
青小莫32 分钟前
c语言-数据结构-二叉树OJ
c语言·开发语言·数据结构·二叉树·力扣
典学长编程34 分钟前
Java从入门到精通!第十一天(Java常见的数据结构)
java·开发语言·数据结构
后端小张39 分钟前
智谱AI图生视频:从批处理到多线程优化
开发语言·人工智能·ai·langchain·音视频
m0dw1 小时前
js迭代器
开发语言·前端·javascript
胡斌附体1 小时前
oracle查询数据结构滤涉及的sql语句
数据结构·sql·oracle
cherishSpring1 小时前
Redis学习笔记
redis·笔记·学习
★YUI★1 小时前
学习游戏制作记录(战斗系统简述以及击中效果)7.22
学习·游戏