C語言循環(huán)隊(duì)列與用隊(duì)列實(shí)現(xiàn)棧問題解析
循環(huán)隊(duì)列
循環(huán)隊(duì)列: 循環(huán)隊(duì)列是一種線性數(shù)據(jù)結(jié)構(gòu),其操作表現(xiàn)基于 FIFO(先進(jìn)先出)原則并且隊(duì)尾被連接在隊(duì)首之后以形成一個(gè)循環(huán)循環(huán)隊(duì)列的好處:可以重新利用隊(duì)列的空間。我們可以利用這個(gè)隊(duì)列之前用過的空間。在一個(gè)普通隊(duì)列里,一旦一個(gè)隊(duì)列滿了,我們就不能插入下一個(gè)元素,即使在隊(duì)列前面仍有空間。但是使用循環(huán)隊(duì)列,我們能使用這些空間去存儲(chǔ)新的值。
題目描述
設(shè)計(jì)你的循環(huán)隊(duì)列實(shí)現(xiàn)。
你的實(shí)現(xiàn)應(yīng)該支持如下操作:
MyCircularQueue(k): 構(gòu)造器,設(shè)置隊(duì)列長度為 k 。
Front: 從隊(duì)首獲取元素。如果隊(duì)列為空,返回 -1 。
Rear: 獲取隊(duì)尾元素。如果隊(duì)列為空,返回 -1 。
enQueue(value): 向循環(huán)隊(duì)列插入一個(gè)元素。如果成功插入則返回真。
deQueue(): 從循環(huán)隊(duì)列中刪除一個(gè)元素。如果成功刪除則返回真。
isEmpty(): 檢查循環(huán)隊(duì)列是否為空。
isFull(): 檢查循環(huán)隊(duì)列是否已滿。
題目鏈接
思路分析
循環(huán)隊(duì)列和普通隊(duì)列對比。
循環(huán)隊(duì)列:入隊(duì)需要尾插。出隊(duì)需要頭刪,刪除并不是真正的刪除,只需要使頭指針往后移動(dòng)就可以了,因?yàn)橐貜?fù)利用其空間。真正意義上只需要尾插罷了。尾插的話鏈表和順序表時(shí)間復(fù)雜度相同。綜上所述:所以循環(huán)隊(duì)列用順序表或者鏈表實(shí)現(xiàn)都可以,差異不大。要真正的誰更優(yōu),因?yàn)轫樞虮砦锢砜臻g是連續(xù)的,CPU緩存命中率高。所以順序表更好一點(diǎn)。
普通隊(duì)列:入隊(duì)需要尾插,出隊(duì)需要頭刪,頭刪需要真正的刪除,但是順序表頭刪后還需要覆蓋,效率低,所以用單鏈表實(shí)現(xiàn)。
思路 :
1.創(chuàng)建循環(huán)隊(duì)列結(jié)構(gòu)體,包含一個(gè)順序表a,頭指針和尾指針head和tail,隊(duì)列的長度k。
2.要為隊(duì)列多開一個(gè)空間,這樣可以正確判斷隊(duì)列是否為空,或者是否滿了。紅色的空間是多開的一個(gè)空間。
3.循環(huán)隊(duì)列的關(guān)鍵在于判斷隊(duì)列是否為空或者隊(duì)列是否滿了。為空:只有當(dāng)tail == head才為空。
滿了:分兩種情況。情況1.當(dāng)tail == 隊(duì)列長度(k) && head == 0時(shí)
情況2:當(dāng)tail+1 == head時(shí)
代碼實(shí)現(xiàn)
代碼寫好后。經(jīng)過我數(shù)十次的調(diào)試,bug終于調(diào)完。
說一說我遇到的bug:
1.第一次提交發(fā)現(xiàn)循環(huán)隊(duì)列的創(chuàng)建失敗。原因是沒有對循環(huán)隊(duì)列的結(jié)構(gòu)體進(jìn)行初始化。
2.在獲取尾部元素的時(shí)候報(bào)錯(cuò)。漏掉了一個(gè)特殊情況,就是假如尾部的元素在第一個(gè)怎么辦?這時(shí)候tail-1就變?yōu)?1了。數(shù)組產(chǎn)生了越界。這時(shí)候報(bào)的錯(cuò)誤是一堆看不懂的內(nèi)存錯(cuò)誤,讓人摸不著頭腦。
3.在入隊(duì)的時(shí)候發(fā)生錯(cuò)誤。邏輯錯(cuò)誤。要牢記tail指向的是即將入隊(duì)的空間。應(yīng)該先入隊(duì),tail再++。
typedef struct { int* a; int head; int tail; int k; } MyCircularQueue; bool myCircularQueueIsEmpty(MyCircularQueue* obj) ; bool myCircularQueueIsFull(MyCircularQueue* obj) ; MyCircularQueue* myCircularQueueCreate(int k) { //給結(jié)構(gòu)體指針變量開辟空間,否則為野指針。 MyCircularQueue* new =(MyCircularQueue*)malloc(sizeof(MyCircularQueue)); int* b = (int*)malloc(sizeof(int)*(k+1)); new->a = b; new->head = 0; new->tail = 0; new->k = k; return new; } bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) { assert(obj); if(myCircularQueueIsFull(obj)) { return false; } obj->a[obj->tail] = value; if(obj->tail == obj->k) { obj->tail = 0; } else { obj->tail++; } return true; } bool myCircularQueueDeQueue(MyCircularQueue* obj) { assert(obj); if(myCircularQueueIsEmpty(obj)) { return false; } if(obj->head == obj->k) { obj->head = 0; } else { obj->head++; } return true; } int myCircularQueueFront(MyCircularQueue* obj) { assert(obj); if(myCircularQueueIsEmpty(obj)) { return -1; } return obj->a[obj->head]; } int myCircularQueueRear(MyCircularQueue* obj) { assert(obj); if(myCircularQueueIsEmpty(obj)) { return -1; } if(obj->tail == 0) { return obj->a[obj->k]; } return obj->a[obj->tail-1]; } bool myCircularQueueIsEmpty(MyCircularQueue* obj) { assert(obj); return obj->head == obj->tail; } bool myCircularQueueIsFull(MyCircularQueue* obj) { assert(obj); if(obj->head==0 && obj->tail == obj->k) { return true; } else { return obj->head == obj->tail+1; } } void myCircularQueueFree(MyCircularQueue* obj) { assert(obj); free(obj->a); free(obj); }
用隊(duì)列實(shí)現(xiàn)棧
用兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)棧的基本功能。用C語言做,需要先創(chuàng)建兩個(gè)隊(duì)列。
題目描述
請你僅使用兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)后入先出(LIFO)的棧,并支持普通棧的全部四種操作(push、top、pop 和 empty)。
題目鏈接
思路分析
此題和C語言循環(huán)隊(duì)列與用隊(duì)列實(shí)現(xiàn)棧問題解析。差不多。
思路:
1.壓棧就是誰不為空就往誰里面進(jìn)行入隊(duì)。
2.出棧就是先把不為空的一個(gè)隊(duì)列里面的前k-1個(gè)元素入隊(duì)到為空那個(gè)隊(duì)列。然后再把不為空那個(gè)隊(duì)列的元素pop掉。
代碼實(shí)現(xiàn)
我遇到的bug
1.判斷到底哪個(gè)隊(duì)列是空隊(duì)列,可以用假設(shè)法。假設(shè)其中一個(gè)為空,另一個(gè)不為空,然后再做調(diào)整。這樣后續(xù)就方便了。
//假設(shè)后調(diào)整 Queue* emptyQ = &obj->q1; Queue* nonEmptyQ = &obj->q2; if(!QueueEmpty(&obj->q1)) { emptyQ = &obj->q2; nonEmptyQ = &obj->q1; }
2.移動(dòng)前k-1個(gè)元素到另一個(gè)隊(duì)列不能用遍歷。遍歷會(huì)麻煩,且每一次出隊(duì),頭指針會(huì)自動(dòng)移動(dòng)。所以直接用算出隊(duì)列的長度解決移動(dòng)前k-1元素。
typedef int QDataType; typedef struct QueueNode { QDataType data; struct QueueNode* next; }QNode; typedef struct Queue { QNode* head; QNode* tail; //size_t size; }Queue; void QueueInit(Queue* pq); void QueueDestory(Queue* pq); void QueuePush(Queue* pq, QDataType x); void QueuePop(Queue* pq); bool QueueEmpty(Queue* pq); size_t QueueSize(Queue* pq); QDataType QueueFront(Queue* pq); QDataType QueueBack(Queue* pq); void QueueInit(Queue* pq) { assert(pq); pq->head = pq->tail = NULL; } void QueueDestory(Queue* pq) { assert(pq); QNode* cur = pq->head; while (cur) { QNode* next = cur->next; free(cur); cur = next; } pq->head = pq->tail = NULL; } void QueuePush(Queue* pq, QDataType x) { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode)); assert(newnode); newnode->data = x; newnode->next = NULL; if (pq->tail == NULL) { assert(pq->head == NULL); pq->head = pq->tail = newnode; } else { pq->tail->next = newnode; pq->tail = newnode; } } void QueuePop(Queue* pq) { assert(pq); assert(pq->head && pq->tail); 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; } } bool QueueEmpty(Queue* pq) { assert(pq); return pq->head == NULL; } size_t QueueSize(Queue* pq) { assert(pq); QNode* cur = pq->head; size_t size = 0; while (cur) { size++; cur = cur->next; } return size; } QDataType QueueFront(Queue* pq) { assert(pq); assert(pq->head); return pq->head->data; } QDataType QueueBack(Queue* pq) { assert(pq); assert(pq->tail); return pq->tail->data; } //創(chuàng)建兩個(gè)隊(duì)列 typedef struct { Queue q1; Queue q2; } MyStack; //初始化兩個(gè)隊(duì)列 MyStack* myStackCreate() { MyStack* new = (MyStack*)malloc(sizeof(MyStack)); assert(new); QueueInit(&new->q1); QueueInit(&new->q2); return new; } //誰不為空就在誰里面入隊(duì) void myStackPush(MyStack* obj, int x) { assert(obj); if(!QueueEmpty(&obj->q2)) { QueuePush(&obj->q2, x); } else { QueuePush(&obj->q1, x); } } int myStackPop(MyStack* obj) { assert(obj); //假設(shè)后調(diào)整 Queue* emptyQ = &obj->q1; Queue* nonEmptyQ = &obj->q2; if(!QueueEmpty(&obj->q1)) { emptyQ = &obj->q2; nonEmptyQ = &obj->q1; } while(QueueSize(nonEmptyQ) > 1) { int front = QueueFront(nonEmptyQ); QueuePush(emptyQ, front); QueuePop(nonEmptyQ); } int top = QueueFront(nonEmptyQ); QueuePop(nonEmptyQ); return top; } int myStackTop(MyStack* obj) { assert(obj); int ret = 0; if(!QueueEmpty(&obj->q1)) { ret = QueueBack(&obj->q1); } else { ret = QueueBack(&obj->q2); } return ret; } bool myStackEmpty(MyStack* obj) { assert(obj); return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2); } void myStackFree(MyStack* obj) { assert(obj); QueueDestory(&obj->q1); QueueDestory(&obj->q2); free(obj); }
到此這篇關(guān)于C語言循環(huán)隊(duì)列與用隊(duì)列實(shí)現(xiàn)棧問題解析的文章就介紹到這了,更多相關(guān)C語言 循環(huán)隊(duì)列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言數(shù)據(jù)結(jié)構(gòu)進(jìn)階之棧和隊(duì)列的實(shí)現(xiàn)
棧和隊(duì)列,嚴(yán)格意義上來說,也屬于線性表,因?yàn)樗鼈円捕加糜诖鎯?chǔ)邏輯關(guān)系為 "一對一" 的數(shù)據(jù),但由于它們比較特殊,因此將其單獨(dú)作為一章,做重點(diǎn)講解2021-11-11C語言詳解如何應(yīng)用模擬字符串和內(nèi)存函數(shù)
這篇文章主要介紹了C語言詳解如何應(yīng)用模擬字符串和內(nèi)存函數(shù),文章有點(diǎn)長,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02Qt出現(xiàn)假死凍結(jié)現(xiàn)象的原因及解決方法
應(yīng)用程序出現(xiàn)假死或凍結(jié)現(xiàn)象通常是由于一些常見問題所導(dǎo)致的,本文主要介紹了Qt出現(xiàn)假死凍結(jié)現(xiàn)象的原因及解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10C++ vector的介紹及常見功能實(shí)現(xiàn)
這篇文章主要介紹了C++ vector的介紹及模擬實(shí)現(xiàn),vector在實(shí)際中非常的重要,但在實(shí)際中我們只要熟悉常見的接口就可以了,最重要的是理解他的底層原理,要能夠自己模擬實(shí)現(xiàn)出一個(gè)簡單的vector,本文結(jié)合示例代碼給大家詳細(xì)介紹,需要的朋友可以參考下2023-05-05VSCode搭建C/C++編譯環(huán)境的詳細(xì)教程
Visual Studio Code是一款免費(fèi)開源的現(xiàn)代化輕量級(jí)代碼編輯器,支持幾乎所有主流的開發(fā)語言的語法高亮、智能代碼補(bǔ)全、自定義熱鍵、括號(hào)匹配、代碼片段、代碼對比 Diff、GIT 等特性,這篇文章主要介紹了VSCode搭建C/C++編譯環(huán)境,需要的朋友可以參考下2020-05-05C語言驅(qū)動(dòng)開發(fā)之內(nèi)核解鎖與強(qiáng)刪文件
在某些時(shí)候我們的系統(tǒng)中會(huì)出現(xiàn)一些無法被正常刪除的文件,如果想要強(qiáng)制刪除則需要在驅(qū)動(dòng)層面對其進(jìn)行解鎖后才可刪掉,本文為大家介紹了內(nèi)核解鎖與強(qiáng)刪文件的方法,希望對大家有所幫助2023-06-06