前言
在做这个题目之前,应当熟悉栈和队列这两种数据结构.栈和队列都是常见的数据结构,它们是基于数组或链表实现的线性数据结构。
栈(Stack):
栈是一种后进先出(Last-In-First-Out,LIFO)的数据结构,只允许在栈顶进行插入和删除操作。栈的基本操作包括入栈(push)、出栈(pop)、查看栈顶元素(top)和判断栈是否为空(empty)。
应用场景:实现程序调用的函数堆栈、表达式求值、括号匹配检验等。
队列(Queue):
队列是一种先进先出(First-In-First-Out,FIFO)的数据结构,只允许在队尾插入元素,在队头删除元素。队列的基本操作包括入队(enqueue)、出队(dequeue)、查看队头元素(front)和判断队列是否为空(empty)。
一、题目介绍
题目来源于–力扣
题目链接:传送门
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
● void push(int x) 将元素 x 压入栈顶。
● int pop() 移除并返回栈顶元素。
● int top() 返回栈顶元素。
● boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
(1) 模拟栈的结构:
将模拟栈的结构定义为两个队列
typedef struct { Queue q1; Queue q2; } MyStack;
(2 初始化模拟栈(myStackCreate)
调用两个栈对应的初始化函数.
代码实现:
MyStack* myStackCreate() { MyStack* stack=( MyStack*)malloc(sizeof(MyStack));//开辟栈所占的空间(两个队列) //初始化栈 QueueInit(&stack->q1); QueueInit(&stack->q2); return stack; }
(3) 压栈(myStackPush)
对于入栈操作,谁是空队列,就往这个队列中正常压数据,模拟压栈的过程.
代码实现:
void myStackPush(MyStack* obj, int x) { if(!QueueEmpty(&obj->q1))//如果其中一个队列是空,就往空的队列中插入元素 { QueuePush(&obj->q1,x); } else{ QueuePush(&obj->q2,x); } }
(4) 出栈(myStackPop)
出队列相对麻烦一些:
- 倒数据,将非空队列中的数据只保留队尾数据以外,其他全部导入另一个队列(空).
- 保存队尾数据.
- 将剩余的队尾数据出栈,并返回队尾.
代码实现:
int myStackPop(MyStack* obj) { Queue* empty=&obj->q1;//假设q1是空队列 Queue* Notempty=&obj->q2; if(!QueueEmpty(&obj->q1))//如果假设错误,则说明q2才是空队列 { empty=&obj->q2; Notempty=&obj->q1; } //将除了最后一个要删除的元素以外其他元素,倒数据到空队列 while(QueueSize(Notempty)>1) { //将有元素的队列中的队头的值放入空队列中 QueuePush(empty,QueueFront(Notempty)); //弹出这个队头元素 QueuePop(Notempty); } int top=QueueFront(Notempty); QueuePop(Notempty);//删除剩下的最后一个元素. return top; }
(5) 栈顶元素(myStackTop)
哪个队列有数据,则将这个队列的队尾元素返回即可.
代码实现:
int myStackTop(MyStack* obj) { if(!QueueEmpty(&obj->q1))//找到有元素的队列,将其队列尾部的数据打印出来 { return QueueBack(&obj->q1); } else{ return QueueBack(&obj->q2); } }
(6) 栈空(myStackEmpty)
两个队列中都没有数据则表示栈为空.
代码实现:
bool myStackEmpty(MyStack* obj) { if(QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2))//如果都为空,则为空栈 { return true; } else return false; //return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2); }
(7)栈的释放(myStackFree)
代码实现:
void myStackFree(MyStack* obj) { //先释放栈中申请的链式队列 QueueDestroy(&obj->q1); QueueDestroy(&obj->q2); //最后释放栈这个结构体 free(obj); }
二、总代码示例:
//手撕队列 /* ... */ typedef struct { Queue q1; Queue q2; } MyStack; MyStack* myStackCreate() { MyStack* stack=( MyStack*)malloc(sizeof(MyStack));//开辟栈所占的空间(两个队列) //初始化栈 QueueInit(&stack->q1); QueueInit(&stack->q2); return stack; } void myStackPush(MyStack* obj, int x) { if(!QueueEmpty(&obj->q1))//如果其中一个队列是空,就往空的队列中插入元素 { QueuePush(&obj->q1,x); } else{ QueuePush(&obj->q2,x); } } int myStackPop(MyStack* obj) { Queue* empty=&obj->q1;//假设q1是空队列 Queue* Notempty=&obj->q2; if(!QueueEmpty(&obj->q1))//如果假设错误,则说明q2才是空队列 { empty=&obj->q2; Notempty=&obj->q1; } //将除了最后一个要删除的元素以外其他元素,倒数据到空队列 while(QueueSize(Notempty)>1) { //将有元素的队列中的队头的值放入空队列中 QueuePush(empty,QueueFront(Notempty)); //弹出这个队头元素 QueuePop(Notempty); } int top=QueueFront(Notempty); QueuePop(Notempty);//删除剩下的最后一个元素. return top; } int myStackTop(MyStack* obj) { if(!QueueEmpty(&obj->q1))//找到有元素的队列,将其队列尾部的数据打印出来 { return QueueBack(&obj->q1); } else{ return QueueBack(&obj->q2); } } bool myStackEmpty(MyStack* obj) { if(QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2))//如果都为空,则为空栈 { return true; } else return false; //return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2); } void myStackFree(MyStack* obj) { //先释放栈中申请的链式队列 QueueDestroy(&obj->q1); QueueDestroy(&obj->q2); //最后释放栈这个结构体 free(obj); } /** * 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); */
手撕队列的源码
//手撕队列 typedef int QDatatype; typedef struct QueueNode { struct QueueNode* next; QDatatype data; }QNode; typedef struct Queue { QNode* head; QNode* tail; int size; }Queue; void QueueInit(Queue* pq); void QueueDestroy(Queue* pq); void QueuePush(Queue* pq, QDatatype x); void QueuePop(Queue* pq); int QueueSize(Queue* pq); bool QueueEmpty(Queue* pq); QDatatype QueueFront(Queue* pq); QDatatype QueueBack(Queue* pq); void QueueInit(Queue* pq)//队列的初始化 { assert(pq); pq->head = pq->tail = NULL; pq->size = 0; } void QueueDestroy(Queue* pq)//销毁队列操作 { assert(pq); QNode* cur = pq->head; QNode* next = cur; while (next) { next = cur->next; free(cur); cur = next; } pq->head = pq->tail = NULL; pq->size = 0; } void QueuePush(Queue* pq, QDatatype x)//入队列操作 { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode)); newnode->data = x; newnode->next = NULL; if (newnode == NULL) { perror("newnode malloc fail:"); return; } if (pq->head == NULL)//第一次插入 { assert(pq->tail==NULL); pq->head = pq->tail = newnode; } else { pq->tail->next = newnode; pq->tail = newnode; } pq->size++; } bool QueueEmpty(Queue* pq)//队列的判空操作 { assert(pq); if (pq->head == pq->tail && pq->head == NULL) { return true; } return false; } void QueuePop(Queue* pq)//出队列 { assert(pq); assert(!QueueEmpty(pq)); if (pq->head->next == NULL)//代表还剩下一个结点 { free(pq->head);//释放这个结点. pq->head = pq->tail = NULL; } else { QNode* next = pq->head->next; free(pq->head); pq->head = next; } pq->size--; } int QueueSize(Queue* pq)//队列元素的大小 { assert(pq); return pq->size; } QDatatype QueueFront(Queue* pq)//队首元素 { assert(pq); assert(pq->head); return pq->head->data; } QDatatype QueueBack(Queue* pq)//队尾元素 { assert(pq); assert(pq->head); return pq->tail->data; }