力扣 225. 用佇列實現棧
題目來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/implement-stack-using-queues
使用佇列實現棧的下列操作:
push(x) – 元素 x 入棧
pop() – 移除棧頂元素
top() – 獲取棧頂元素
empty() – 返回棧是否為空
注意:
你只能使用佇列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 這些操作是合法的。
你所使用的語言也許不支援佇列。 你可以使用 list 或者 deque(雙端佇列)來模擬一個佇列 , 只要是標準的佇列操作即可。
一、實現佇列
先實現佇列的基本操作,之後再實現棧。
typedef int QDataType;
typedef struct QNode{
struct QNode* _next;
QDataType _data;
}QNode;
typedef struct Queue{
QNode* _front;
QNode* _rear;
}Queue;
void queueInit(Queue* q){
q->_front = q->_rear = NULL;
}
QNode* createNode(QDataType data){
QNode* node = (QNode*)malloc(sizeof(QNode));
node->_data = data;
node->_next = NULL;
return node;
}
void queuePush(Queue* q, QDataType data){
if (q == NULL){ //注意判空
return;
}
QNode* node = createNode(data);
if (q->_front == NULL){ //若入隊的是第一個元素,需要特殊處理
q-> _front = q->_rear = node;
}
else{
q->_rear->_next = node;
q->_rear = node;
}
}
void queuePop(Queue* q){
if (q->_front){ //同樣需要判斷佇列中是否還剩餘元素
QNode* next = q->_front->_next;
free(q->_front);
q->_front = next;
if (q->_front == NULL){ //出隊最後一個元素後,隊尾指標需要設為NULL
q->_rear = NULL; //否則會產生野指標
}
}
}
QDataType queueFront(Queue* q){
return q->_front->_data;
}
QDataType queueBack(Queue* q){
return q->_rear->_data;
}
QDataType queueSize(Queue* q){
if (q == NULL){
return 0;
}
int num = 0;
QNode* cur = q->_front;
while (cur){
num++;
cur = cur->_next;
}
return num;
}
int queueEmpty(Queue* q){
if (q->_front == NULL){
return 1;
}
else{
return 0;
}
}
void queueDestroy(Queue* q){
QNode* cur = q->_front;
while (cur){
QNode* next = cur->_next;
free(cur);
cur = next;
}
q->_rear = NULL;
}
二、用佇列實現棧
佇列實現棧的基本思路是:將要出棧元素以外的所有元素挪到此元素之後,再執行出隊。例如,佇列中有1、2、3、4、5五個元素,現在進行出棧操作,那麼就是要讓元素5出棧。此時,我們將1、2、3、4挪到5後面,使得5成為隊頭元素,再使用出隊函式即可。即變化為5、1、2、3、4後進行出隊,這樣就模擬了出棧(後進先出)的操作。
typedef struct {
Queue q;
} MyStack;
/** Initialize your data structure here. */
MyStack* myStackCreate() {
MyStack* ms = (MyStack*)malloc(sizeof(MyStack));
queueInit(&ms->q);
return ms;
}
/** Push element x onto stack. */
void myStackPush(MyStack* obj, int x) {
queuePush(&obj->q, x);
}
定義MyStack結構體。MyStack實質上就是佇列,也就是說,用一個佇列就可以實現一個棧。棧的初始化和入棧操作實際上就是佇列的初始化和入隊操作。
/** Removes the element on top of the stack and returns that element. */
int myStackPop(MyStack* obj) {
int size = queueSize(&obj->q);
while (size > 1){
int front = queueFront(&obj->q);
queuePop(&obj->q);
queuePush(&obj->q, front);
size--;
}
int ret = queueFront(&obj->q);
queuePop(&obj->q);
return ret;
}
重點來了,根據剛才所敘述的思路編寫程式碼,實現出棧操作。首先需要一個size變數儲存佇列中元素的個數,將隊頭元素放入front變數中,然後出隊。再將front變數入隊,相當於完成了一個元素從隊頭到隊尾的搬移。使用迴圈結構重複這一操作,直到需要出棧的元素來到隊頭。最後出隊(相當於出棧)。然後根據題目要求,返回出棧元素的值。
/** Get the top element. */
int myStackTop(MyStack* obj) {
return queueBack(&obj->q);
}
/** Returns whether the stack is empty. */
bool myStackEmpty(MyStack* obj) {
if (queueEmpty(&obj->q) == 1){
return true;
}
return false;
}
void myStackFree(MyStack* obj) {
queueDestroy(&obj->q);
free(obj);
}
這三個函式難度不大。取出棧頂元素等價於取出隊尾元素,判斷棧空等價於判斷佇列空,銷燬棧等價於銷燬佇列。因此直接呼叫之前編寫好的佇列相關操作即可。