【数据结构】— 『队列』的实现以及LeetCode队列练习题
??? ?各位大佬們好!很榮幸能夠得到您的訪問,讓我們一起在編程道路上任重道遠!?
??博客專欄:【數據結構初階】?
? 本篇內容簡介:數據結構初階中的隊列的實現以及LeetCode練習!
? 了解作者:勵志成為一名編程大牛的學子,目前是大二的編程小白。
?勵志術語:編程道路的乏味,讓我們一起學習變得有趣!
文章目錄
🌔 隊列的概念及結構
🌗 隊列的實現
🌒 隊列的鏈式結構
?🌒 隊列的初始化
?🌒 隊尾入數據
?🌒 隊頭出數據
🌒 獲取隊頭的數據
🌒 獲取隊尾的數據
🌒 獲取隊列有效元素個數
🌒 判斷隊列是否為空
🌒 隊列的銷毀
🌒 測試隊列接口功能
?🌔 隊列源代碼
🌗 Queue.c文件
🌗 Queue.h文件
🌗 test.c文件
🌔 225.用隊列實現棧
🌗 題解思路
?🌗 題解代碼
🌔 232.用棧實現隊列
?🌗 題解思路
🌗 題解代碼
🌗 結束語
🌔 隊列的概念及結構
隊列:只允許在一端進行插入數據操作,在另一端進行刪除數據操作的特殊線性表,隊列具有先進先出 FIFO(First in First out)。
入隊列:進行插入操作的一端稱為隊尾。
出隊列:進行刪除操作的一端稱為隊頭。
🌗 隊列的實現
隊列可以是數組或者鏈表的結構實現,但是使用鏈表的結構實現更優一點。因為如果使用數組的結構,出隊列在數組頭上的數據,效率會比較低。在這里我們使用鏈表來實現隊列。(數組不適合數組頭頻繁刪除或者數組中插入數據)。
🌒 隊列的鏈式結構
//隊列的鏈式結構 typedef int QDataType;typedef struct QListNode {struct QListNode* next;QDataType Data; }QNode;//隊列的結構 typedef struct Queue {QNode* front;QNode* back;int size;//記錄隊列節點的個數 }Queue;?🌒 隊列的初始化
初始化隊列就是要使頭指針與尾指針都置為空,將size也置為空。
void QueueInit(Queue* pq) {//斷言隊列不能為空assert(pq);pq->front = pq->back = NULL;pq->size = 0; }?🌒 隊尾入數據
首先我們要先創造新的要插入的節點,1.如果是第一個插入數據,將頭指針與尾指針都指向newnode;2.平常的尾插,先將newnode尾插到back指針后,再將back指針指向尾節點。
void QueuePush(Queue* pq, QDataType x) {assert(pq);//先創造節點,再進行鏈接QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");exit(-1);}//初始化節點newnode->Data = x;newnode->next = NULL;//鏈接,考慮尾節點是空,還是非空if (pq->back == NULL){pq->front = pq->back = newnode;}else{pq->back->next = newnode;pq->back = newnode;}pq->size++;//隊列節點++ }?🌒 隊頭出數據
隊頭出數據時,當隊頭為空時就不能再出數據了,需要進行判空處理。
1. 當隊列只剩余一個數據時,如果直接free,會造成back的野指針問題,所以我們需要單獨判斷這種情況。
2. 我們需要記錄要刪除的節點,再將front指向下一個,最后置空。
void QueuePop(Queue* pq) {assert(pq);//判斷只剩一個數據時if (pq->front == NULL){free(pq->front);pq->front = pq->back = NULL;}else{QNode* del = pq->front;pq->front = pq->front->next;free(del);del = NULL;}pq->size--;//出數據需要--size }🌒 獲取隊頭的數據
//獲取隊頭的數據 QDataType QueueFront(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->front->Data; }🌒 獲取隊尾的數據
//獲取隊尾的數據 QDataType QueueBack(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->back->Data;}🌒 獲取隊列有效元素個數
因為我們在隊列的結構體中加上了size記錄元素個數,所以我們在這里可以直接返回。
//獲取隊列中有效元素的個數 int QueueSize(Queue* pq) {assert(pq);return pq->size; }🌒 判斷隊列是否為空
如果隊列為空返回非0值,如果是非空返回0。
//隊列的判空 bool QueueEmpty(Queue* pq) {assert(pq);return pq->front == NULL && pq->back == NULL; }🌒 隊列的銷毀
因為我們這里使用鏈表實現,所以我們要將鏈表的節點,一個一個釋放。
//隊列的銷毀 void QueueDestroy(Queue* pq) {assert(pq);QNode* cur = pq->front;while (cur != NULL){QNode* del = cur;cur = cur->next;free(del);}pq->front = pq->back = NULL; }🌒 測試隊列接口功能
int main() {Queue q;QueueInit(&q);//隊尾插入數據QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePush(&q, 5);while (!QueueEmpty(&q)){//獲取隊頭的數據printf("%d ", QueueFront(&q));QueuePop(&q);}printf("\n");QueueDestroy(&q);return 0; }?🌔 隊列源代碼
🌗 Queue.c文件
#include"Queue.h"void QueueInit(Queue* pq) {//斷言隊列不能為空assert(pq);pq->front = pq->back = NULL;pq->size = 0; }void QueuePush(Queue* pq, QDataType x) {assert(pq);//先創造節點,再進行鏈接QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");exit(-1);}//初始化節點newnode->Data = x;newnode->next = NULL;//鏈接,考慮尾節點是空,還是非空if (pq->back == NULL){pq->front = pq->back = newnode;}else{pq->back->next = newnode;pq->back = newnode;}pq->size++;//隊列節點++ }void QueuePop(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));//判斷只剩一個數據時if (pq->front == NULL){free(pq->front);pq->front = pq->back = NULL;}else{QNode* del = pq->front;pq->front = pq->front->next;free(del);del = NULL;}pq->size--;//出數據需要--size }//獲取隊頭的數據 QDataType QueueFront(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->front->Data; }//獲取隊尾的數據 QDataType QueueBack(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->back->Data;}//獲取隊列中有效元素的個數 int QueueSize(Queue* pq) {assert(pq);return pq->size; }//隊列的判空 bool QueueEmpty(Queue* pq) {assert(pq);return pq->front == NULL && pq->back == NULL; }//隊列的銷毀 void QueueDestroy(Queue* pq) {assert(pq);QNode* cur = pq->front;while (cur != NULL){QNode* del = cur;cur = cur->next;free(del);}pq->front = pq->back = NULL; }🌗 Queue.h文件
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once#include<stdio.h> #include<assert.h> #include<stdlib.h> #include<stdbool.h>//隊列的鏈式結構 typedef int QDataType;typedef struct QListNode {struct QListNode* next;QDataType Data; }QNode;//隊列的結構 typedef struct Queue {QNode* front;QNode* back;int size;//記錄隊列節點的個數 }Queue;//初始化隊列 void QueueInit(Queue* pq);//隊尾入數據 void QueuePush(Queue* pq, QDataType x);//隊尾出數據 void QueuePop(Queue* pq);//獲取隊頭的數據 QDataType QueueFront(Queue* pq);//獲取隊尾的數據 QDataType QueueBack(Queue* pq);//獲取隊列中有效元素的個數 int QueueSize(Queue* pq);//隊列的判空 bool QueueEmpty(Queue* pq);//隊列的銷毀 void QueueDestroy(Queue* pq);🌗 test.c文件
#include"Queue.h"int main() {Queue q;QueueInit(&q);//隊尾插入數據QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePush(&q, 5);while (!QueueEmpty(&q)){//獲取隊頭的數據printf("%d ", QueueFront(&q));QueuePop(&q);}printf("\n");QueueDestroy(&q);return 0; }🌔 225.用隊列實現棧
LeeCode題目鏈接:使用兩個棧實現隊列。OJ
題目描述:
🌗 題解思路
實現棧的結構:在此之前我們需要隊列的結構,不過還好我們在前面實現過一個隊列了,這里我們直接用。這里我們定義兩個隊列,一個q1,一個q2。
?
創造棧:這里我們不能像創造隊列一樣,
Queue q;
return &q;
因為局部變量出了作用域就銷毀,所以我們需要malloc一個棧,并且初始化,再返回。
?
入棧:哪個隊列不為空,就往哪個隊列入數據。
?
出棧:假設一個隊列為空,一個隊列不為空,將不為空隊列的數據導入為空隊列中,至原來不為空的隊列還剩一個數據。再記錄最后一個數據,并且返回。
?
獲取棧頂數據:哪個隊列不為空,就獲取哪個隊列中的隊尾的數據。
?
判斷棧是否為空:當兩個隊列都為空時,棧就為空。
?
棧的銷毀:因為在棧中,有兩個隊列,所以先銷毀兩個隊列,再釋放棧。
?
?🌗 題解代碼
// 兩個隊列 typedef struct {Queue q1;Queue q2; } MyStack;MyStack* myStackCreate() {// 需要malloc objMyStack* obj=(MyStack*)malloc(sizeof(MyStack));//初始化QueueInit(&obj->q1);QueueInit(&obj->q2);return obj; }void myStackPush(MyStack* obj, int x) {//兩個不為空就push哪個if(!QueueEmpty(&obj->q1)){//入數據QueuePush(&obj->q1,x);}else{QueuePush(&obj->q2,x);} }int myStackPop(MyStack* obj) { //要返回棧頂的數據//Pop不為空隊列 假設q1為空MyStack* empty=&obj->q1;MyStack* nonempty=&obj->q2;if(!QueueEmpty(&obj->q1)){empty=&obj->q2;nonempty=&obj->q1;}//倒數據 還剩下一個數據while(QueueSize(nonempty)>1){//不為空隊列的頭數據QueuePush(empty,QueueFront(nonempty));QueuePop(nonempty);}//返回棧頂元素int top=QueueFront(nonempty);QueuePop(nonempty);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) {//先銷毀隊列,再free棧QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj); }🌔 232.用棧實現隊列
LeetCode題目鏈接:用兩個棧實現隊列。OJ
題目描述:
?🌗 題解思路
隊列結構:還是一樣需要棧的所有接口實現,在這里我們定義兩個棧,
一個棧叫Push棧:專門用來隊列的插入數據。
另一個棧叫Pop棧:專門用來實現出隊列的操作。
?
創造隊列:還是一樣需要malloc一個隊列,并且初始化,最后返回。
?
入隊列:直接往Push棧里面插入數據。?
?
出隊列:判斷需不需要將數據從Push棧中全部導入Pop棧中,如果Pop棧中沒有數據,就說明需要倒數據。因為是棧的性質,所以隊頭的數據就是棧頂的數據,就是倒過去之后棧頂的數據。(需要Pop操作)
?
獲取隊頭的數據:也是一樣判斷是否需要倒數據,再記錄Pop棧頂的數據,返回。(不需要Pop操作)
?
隊列的判空:兩個棧都為空時,隊列就為空。?
?
隊列的銷毀:先銷毀兩個棧,再釋放隊列。
?
🌗 題解代碼
typedef struct {//一個棧用來Push,一個棧用來PopStack PushST;Stack PopST; } MyQueue;MyQueue* myQueueCreate() {MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));//進行初始化StackInit(&obj->PushST);StackInit(&obj->PopST);return obj; }void myQueuePush(MyQueue* obj, int x) {//直接往PushST的棧入數據StackPush(&obj->PushST,x); }void PushST_To_PopST(MyQueue* obj) {if(StackEmpty(&obj->PopST)){while(!StackEmpty(&obj->PushST)){//倒PushST棧頂的數據StackPush(&obj->PopST,StackTop(&obj->PushST));//刪除這個數據StackPop(&obj->PushST);}} }int myQueuePop(MyQueue* obj) {//考慮是否倒數據PushST_To_PopST(obj);//返回隊列開頭的數據int front=StackTop(&obj->PopST);StackPop(&obj->PopST);return front; }int myQueuePeek(MyQueue* obj) {//直接返回隊列頭的數據PushST_To_PopST(obj);int front=StackTop(&obj->PopST);return front; }bool myQueueEmpty(MyQueue* obj) {return StackEmpty(&obj->PushST) && StackEmpty(&obj->PopST); }void myQueueFree(MyQueue* obj) {StackDestroy(&obj->PushST);StackDestroy(&obj->PopST);free(obj); }🌗 結束語
🎈?相隔千里,不能陪各位大佬在中秋節一起賞月,但是我們還能看到同一個月亮。中秋節祝各位大佬中秋快樂。
【寫在最后·想告訴你】
在互聯網這個行業里
任何時候都要學好技術
永遠都是?技術為王
總結
以上是生活随笔為你收集整理的【数据结构】— 『队列』的实现以及LeetCode队列练习题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 201871010104-陈园园 《面向
- 下一篇: 入门IOS客户端开发(一)