
🔥个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题
🍉学习方向:C/C++方向
⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平

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


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

(一)思路
我们的思路是:入栈:往不为空的队列中插入数据;出栈:把不为空队列中前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);
*/
二、用栈实现队列问题
博主题解链接:三步走方法用栈实现队列
题目描述:

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

(一)思路
题目分析:

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

思路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语言基础,最好要学过数据结构与算法的算法复杂度和链表的知识,才能写出复杂度较优的代码来。大家一定要自己动手敲一敲,不敲的话不仅容易忘记,也不方便将来复习。