1. 程式人生 > 其它 >力扣 225. 用佇列實現棧

力扣 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(雙端佇列)來模擬一個佇列 , 只要是標準的佇列操作即可。

你可以假設所有操作都是有效的(例如, 對一個空的棧不會呼叫 pop 或者 top 操作)。


一、實現佇列

先實現佇列的基本操作,之後再實現棧。

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);
}

這三個函式難度不大。取出棧頂元素等價於取出隊尾元素,判斷棧空等價於判斷佇列空,銷燬棧等價於銷燬佇列。因此直接呼叫之前編寫好的佇列相關操作即可。
在這裡插入圖片描述