日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

我幼儿园的弟看了都直呼简单的【栈和队列】

發(fā)布時(shí)間:2023/12/8 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 我幼儿园的弟看了都直呼简单的【栈和队列】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 1. 棧
    • 1.1 棧的概念及結(jié)構(gòu)
    • 1.2 實(shí)現(xiàn)棧
  • 2. 隊(duì)列
    • 2.1 隊(duì)列的概念及結(jié)構(gòu)
    • 2.2 隊(duì)列的實(shí)現(xiàn)
  • 3. 概念選擇題
  • 4. 棧和隊(duì)列OJ題
    • 4.1 括號(hào)匹配問(wèn)題
    • 4.2 用隊(duì)列實(shí)現(xiàn)棧
    • 4.3 用棧實(shí)現(xiàn)隊(duì)列
    • 4.4 設(shè)計(jì)循環(huán)隊(duì)列


1. 棧

1.1 棧的概念及結(jié)構(gòu)

棧:一種特殊的線性表(在邏輯上是連續(xù)存儲(chǔ)的,物理上不一定連續(xù)),其只允許在固定的一端進(jìn)行插入和刪除元素操作。
進(jìn)行數(shù)據(jù)插入和刪除操作的一端稱為棧頂,另一端稱為棧底棧中的數(shù)據(jù)元素遵守后進(jìn)先出LIFO(Last In First Out)的原則。

例如上面在棧中的數(shù)據(jù)只能先依次拿出棧頂?shù)臄?shù)據(jù),出棧的順序依此是4,3,2,1,入棧時(shí)是1,2,3,4,所以后進(jìn)先出也可以理解為先進(jìn)后出。

壓棧:棧的插入操作叫做進(jìn)棧/壓棧/入棧,入數(shù)據(jù)在棧頂。
出棧:棧的刪除操作叫做出棧,出數(shù)據(jù)也在棧頂

注意:這里的棧是數(shù)據(jù)結(jié)構(gòu)里的棧,主要是在內(nèi)存堆區(qū)中對(duì)數(shù)據(jù)進(jìn)行管理。而不是操作系統(tǒng)中劃分內(nèi)存區(qū)域中的棧,但是都有一個(gè)特點(diǎn),都遵循后進(jìn)先出。


1.2 實(shí)現(xiàn)棧

棧的實(shí)現(xiàn)一般可以使用數(shù)組或者鏈表實(shí)現(xiàn),相對(duì)而言數(shù)組的結(jié)構(gòu)實(shí)現(xiàn)更優(yōu)一些。因?yàn)閿?shù)組在尾上插入數(shù)據(jù)的代價(jià)比較小,并且數(shù)組的地址是連續(xù)的,訪問(wèn)起來(lái)緩存的利用率也會(huì)更高一些。

但因?yàn)閿?shù)組并不是隨時(shí)動(dòng)態(tài)開(kāi)辟的空間,如果數(shù)組元素滿了需要考慮擴(kuò)容,一次擴(kuò)容原來(lái)的2倍,勢(shì)必會(huì)有一些空間上的浪費(fèi)。
如果比較在意空間,可以使用帶頭雙向鏈表,這是比較方便的,如果使用單鏈表,要把鏈表的頭結(jié)點(diǎn)作為棧頂,尾結(jié)點(diǎn)作為棧底,因?yàn)殒湵淼念^插頭刪比較高效。

代碼實(shí)現(xiàn):

//函數(shù)聲明 #pragma once#include <stdio.h> #include <assert.h> #include <stdlib.h> #include <stdbool.h>//創(chuàng)建棧 typedef int DATATYPE; typedef struct Stack {DATATYPE* stack;int top;int capacity; }Stack;//初始化棧 void InintStack(Stack* ptrs);//入棧 void PushStack(Stack* ptrs, DATATYPE data);//出棧 void PopStack(Stack* ptrs);//訪問(wèn)棧頂數(shù)據(jù) DATATYPE StackTop(Stack* ptrs);//判斷棧是否為空 bool StackEmpty(Stack* ptrs);//數(shù)據(jù)個(gè)數(shù) int StackSize(Stack* ptrs);//銷毀棧 void DestroyStack(Stack* ptrs);

注意:不要直接訪問(wèn)結(jié)構(gòu)體中的數(shù)據(jù),即使非常簡(jiǎn)單也要封裝為一個(gè)函數(shù)來(lái)訪問(wèn)。

//函數(shù)實(shí)現(xiàn) #define _CRT_SECURE_NO_WARNINGS 1 #include "StackQueue.h"//初始化棧 void InintStack(Stack* ptrs) {assert(ptrs);ptrs->stack = NULL;//注意如果初始話top為0//那么棧頂?shù)脑叵聵?biāo)時(shí)top-1ptrs->top = ptrs->capacity = 0; }//檢查容量 void checkSys(Stack* ptrs) { if (ptrs->capacity == ptrs->top){int newCapacity = ptrs->capacity == 0 ? sizeof(DATATYPE) : 2 * ptrs->capacity;DATATYPE* ret = (DATATYPE*)realloc(ptrs->stack, sizeof(DATATYPE) * newCapacity);if (!ret){perror("calloc fali");exit(-1);}ptrs->stack = ret;ptrs->capacity = newCapacity;} }//入棧 void PushStack(Stack* ptrs, DATATYPE data) {assert(ptrs);checkSys(ptrs);ptrs->stack[ptrs->top++] = data; }//出棧 void PopStack(Stack* ptrs) {assert(ptrs);assert(!StackEmpty(ptrs));ptrs->top--; }//訪問(wèn)棧頂數(shù)據(jù) DATATYPE StackTop(Stack* ptrs) {assert(ptrs);assert(!StackEmpty(ptrs));return ptrs->stack[ptrs->top - 1]; }//判斷棧是否為空 bool StackEmpty(Stack* ptrs) {assert(ptrs);return ptrs->top == 0; }//數(shù)據(jù)個(gè)數(shù) int StackSize(Stack* ptrs) {assert(ptrs);return ptrs->top; }//銷毀棧 void DestroyStack(Stack* ptrs) {assert(ptrs);free(ptrs->stack);ptrs->top = ptrs->capacity = 0;ptrs->stack = NULL; } //測(cè)試邏輯 #define _CRT_SECURE_NO_WARNINGS 1 #include "StackQueue.h"void test() {Stack sk;InintStack(&sk);PushStack(&sk, 1);PushStack(&sk, 2);printf("%d ", StackTop(&sk));PopStack(&sk);PushStack(&sk, 3);PushStack(&sk, 4);printf("%d ", StackTop(&sk));PopStack(&sk);PushStack(&sk, 5);PushStack(&sk, 6);//遍歷完棧就相當(dāng)于清空棧了while (!StackEmpty(&sk)){printf("%d ", StackTop(&sk));PopStack(&sk);}DestroyStack(&sk); } int main() {test();return 0; }

2. 隊(duì)列

2.1 隊(duì)列的概念及結(jié)構(gòu)

隊(duì)列:只允許在一端進(jìn)行插入數(shù)據(jù)操作,在另一端進(jìn)行刪除數(shù)據(jù)操作的特殊線性表隊(duì)列具有先進(jìn)先出FIFO(First In First Out)的規(guī)則
入隊(duì)列進(jìn)行插入操作的一端稱為隊(duì)尾
出隊(duì)列:進(jìn)行刪除操作的一端稱為隊(duì)頭
。

2.2 隊(duì)列的實(shí)現(xiàn)

隊(duì)列也可以數(shù)組和鏈表的結(jié)構(gòu)實(shí)現(xiàn),使用鏈表的結(jié)構(gòu)實(shí)現(xiàn)更優(yōu)一些,因?yàn)槿绻褂脭?shù)組的結(jié)構(gòu),出隊(duì)列在數(shù)組頭上出數(shù)據(jù),就需要挪動(dòng)后面的數(shù)據(jù),效率會(huì)比較低。

代碼實(shí)現(xiàn):

//函數(shù)聲明 #pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <stdbool.h> //創(chuàng)建隊(duì)列 typedef int QDataType; typedef struct QueueNode {QDataType data;struct QueueNode* next; }QNode;//因?yàn)殛?duì)列只有頭刪尾插 //因此需要定義兩個(gè)指針 //一個(gè)指向隊(duì)頭,另一個(gè)指向隊(duì)尾 typedef struct Queue {QNode* head;QNode* tail;int size; }Queue;// 初始化隊(duì)列 void QueueInit(Queue* q);// 隊(duì)尾入隊(duì)列 void QueuePush(Queue* q, QDataType data);// 隊(duì)頭出隊(duì)列 void QueuePop(Queue* q);// 獲取隊(duì)列頭部元素 QDataType QueueFront(Queue* q);// 獲取隊(duì)列隊(duì)尾元素 QDataType QueueBack(Queue* q);// 獲取隊(duì)列中有效元素個(gè)數(shù) int QueueSize(Queue* q);// 檢測(cè)隊(duì)列是否為空,如果為空返回非零結(jié)果,如果非空返回0 int QueueEmpty(Queue* q);// 銷毀隊(duì)列 void QueueDestroy(Queue* q); //函數(shù)實(shí)現(xiàn) #define _CRT_SECURE_NO_WARNINGS 1 #include "Queue.h" // 初始化隊(duì)列 void QueueInit(Queue* q) {assert(q);q->head = q->tail = NULL;q->size = 0; }// 隊(duì)尾入隊(duì)列 void QueuePush(Queue* q, QDataType data) {assert(q);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (!newnode){perror("malloc fail");exit(-1);}newnode->data = data;newnode->next = NULL;//當(dāng)頭指針為空需要特殊處理if (q->head == NULL){q->head = q->tail = newnode;}else{q->tail->next = newnode;q->tail = q->tail->next;}q->size++; }// 隊(duì)頭出隊(duì)列 void QueuePop(Queue* q) {assert(q);assert(!QueueEmpty(q));if (q->head->next == NULL){free(q->head);q->head = q->tail = NULL;q->size = 0;}else{QNode* del = q->head;q->head = q->head->next;free(del);del = NULL;q->size--;} }// 獲取隊(duì)列頭部元素 QDataType QueueFront(Queue* q) {assert(q);assert(!QueueEmpty(q));return q->head->data; }// 獲取隊(duì)列隊(duì)尾元素 QDataType QueueBack(Queue* q) {assert(q);assert(!QueueEmpty(q));return q->tail->data; }// 獲取隊(duì)列中有效元素個(gè)數(shù) int QueueSize(Queue* q) {assert(q);return q->size; }// 檢測(cè)隊(duì)列是否為空,如果為空返回非零結(jié)果,如果非空返回0 int QueueEmpty(Queue* q) {assert(q);return q->head == NULL && q->tail == NULL; }// 銷毀隊(duì)列 void QueueDestroy(Queue* q) {assert(q);QNode* cur = q->head;while (cur){QNode* del = cur;cur = cur->next;free(del);del = NULL;}q->head = q->tail = NULL; } //主邏輯測(cè)試 void testQueue() {Queue qq;QueueInit(&qq); QueuePush(&qq, 1);QueuePush(&qq, 2);printf("%d ", QueueFront(&qq));QueuePop(&qq);QueuePush(&qq, 3);QueuePush(&qq, 4);printf("%d ", QueueFront(&qq));QueuePop(&qq);QueuePush(&qq, 5);while (!QueueEmpty(&qq)){printf("%d ", QueueFront(&qq));QueuePop(&qq);}QueueDestroy(&qq); } int main() {//testStack();testQueue();return 0; }

注意:一個(gè)入隊(duì)列順序?qū)?yīng)一個(gè)出隊(duì)列順序,一個(gè)入棧順序?qū)?yīng)多個(gè)出棧順序

3. 概念選擇題

  • 一個(gè)棧的初始 狀態(tài)為空。現(xiàn)將元素1、2、3、4、5、A、B、C、D、E依次入棧,然后再依次出棧,則元素出棧的順序是( )。
    A 12345ABCDE
    B EDCBA54321
    C ABCDE12345
    D 54321EDCBA

  • 若進(jìn)棧序列為 1,2,3,4 ,進(jìn)棧過(guò)程中可以出棧,則下列不可能的一個(gè)出棧序列是()
    A 1,4,3,2
    B 2,3,4,1
    C 3,1,4,2
    D 3,4,2,1

  • 現(xiàn)有一循環(huán)隊(duì)列,其隊(duì)頭指針為front,隊(duì)尾指針為rear;循環(huán)隊(duì)列長(zhǎng)度為N。其隊(duì)內(nèi)有效長(zhǎng)度為?(假設(shè)多給一個(gè)空間,實(shí)際長(zhǎng)度為N)
    A (rear - front + N) % N + 1
    B (rear - front + N) % N
    C (rear - front) % (N + 1)
    D (rear - front + N) % (N - 1)

  • 答案:1.B 2.C 3.B

    第一題很簡(jiǎn)單,先進(jìn)后出原則。
    第二題需要注意的是在入棧的過(guò)程中是可以直接出棧的,比如說(shuō)入棧的順序?yàn)?,2,3,4,那么出棧的順序也是1,2,3,4這是因?yàn)榭梢匀?出1,入2出2…,因此只需要往選項(xiàng)中代入就可以找出不可能的一個(gè)順序。
    一個(gè)入棧順序是可能有多個(gè)出棧順序。
    第三題實(shí)際長(zhǎng)度為N,有效范圍為N-1,直接帶入即可求出當(dāng)前的有效數(shù)據(jù)。

    4. 棧和隊(duì)列OJ題

    4.1 括號(hào)匹配問(wèn)題

    來(lái)源:Leetcode。OJ鏈接

    給定一個(gè)只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判斷字符串是否有效。

    有效字符串需滿足:

    左括號(hào)必須用相同類型的右括號(hào)閉合。
    左括號(hào)必須以正確的順序閉合。


    解題思路:本題解法所需要的數(shù)據(jù)結(jié)構(gòu)正是棧。

  • 當(dāng)遍歷到左括號(hào)時(shí)入棧
  • 遍歷到右括號(hào)時(shí),拿出棧頂?shù)脑剡M(jìn)行比較,如果對(duì)應(yīng)的左括號(hào)不匹配返回0
  • //直接造輪子! //創(chuàng)建棧 //... //把上面實(shí)現(xiàn)的棧原封不動(dòng)的拷貝下來(lái) bool isValid(char * s){Stack sk;InintStack(&sk);for(int i=0; s[i]; ++i){if(s[i] == '(' || s[i] == '[' || s[i] == '{'){//左括號(hào)入棧PushStack(&sk, s[i]);} else{if(StackEmpty(&sk)){//如果第一個(gè)就是右括號(hào),棧為空,說(shuō)明不匹配DestroyStack(&sk);return 0;}DATATYPE ret = StackTop(&sk);if(s[i] == ')' && ret != '(' || s[i] == ']' && ret != '[' || s[i] == '}' && ret != '{'){DestroyStack(&sk);return 0;}//沒(méi)次彈出棧頂元素PopStack(&sk);}}//最后判斷棧里的元素是否為空//為空才為正確答案int flag = StackEmpty(&sk);DestroyStack(&sk);return flag; }

    4.2 用隊(duì)列實(shí)現(xiàn)棧

    來(lái)源:Leetcode。OJ鏈接

    題目描述:請(qǐng)你僅使用兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)后入先出(LIFO)的棧,并支持普通棧的全部四種操作(push、top、pop 和 empty)。

    實(shí)現(xiàn) MyStack 類:

    void push(int x) 將元素 x 壓入棧頂。
    int pop() 移除并返回棧頂元素。
    int top() 返回棧頂元素。
    boolean empty() 如果棧是空的,返回 true ;否則,返回 false 。

    思路:由于隊(duì)列的性質(zhì)是先進(jìn)先出,和棧先進(jìn)后出相反,因此需要用到兩個(gè)隊(duì)列q1和q2,其中一個(gè)為push的隊(duì)列,另一個(gè)為pop的輔助隊(duì)列。
    具體地,當(dāng)pop時(shí),找到兩個(gè)中不為空的隊(duì)列,把不為空的前N-1個(gè)數(shù)據(jù)全部依次push到為空的輔助隊(duì)列,此時(shí)剩下的一個(gè)元素(隊(duì)尾的元素)即為棧頂元素,pop后此隊(duì)列為空。當(dāng)下一次pop時(shí),也是同樣的操作。

    //造輪子 //... //... //把上面實(shí)現(xiàn)的隊(duì)列原封不動(dòng)的拷貝下來(lái)//創(chuàng)建兩個(gè)隊(duì)列 typedef struct {Queue q1;Queue q2; } MyStack; //初始化 MyStack* myStackCreate() {MyStack* obj = (MyStack*)malloc(sizeof(MyStack));QueueInit(&obj->q1);QueueInit(&obj->q2);return obj; } //push元素到空隊(duì)列 void myStackPush(MyStack* obj, int x) {if(!QueueEmpty(&obj->q1)){QueuePush(&obj->q1, x);}else{QueuePush(&obj->q2, x);} } //找到不為空的一個(gè)隊(duì)列 //把前N-1個(gè)數(shù)據(jù)全部push到空隊(duì)列中 //返回最后一個(gè)元素后pop int myStackPop(MyStack* obj) {Queue* empty = &obj->q1, *noempty = &obj->q2;if(!QueueEmpty(empty)){empty = &obj->q2;noempty = &obj->q1;}//非空隊(duì)列的N-1個(gè)元素導(dǎo)入到空隊(duì)列,剩下的一個(gè)就是棧頂元素while(QueueSize(noempty) > 1){QueuePush(empty, QueueFront(noempty));QueuePop(noempty);}int tmp = QueueFront(noempty);QueuePop(noempty);return tmp; } //返回不為空隊(duì)列的隊(duì)尾的元素,即棧頂元素 int myStackTop(MyStack* obj) {if(!QueueEmpty(&obj->q1)){return QueueBack(&obj->q1);}else{return QueueBack(&obj->q2);} } //兩個(gè)隊(duì)列都為空才是空 bool myStackEmpty(MyStack* obj) {return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2); } //釋放隊(duì)列 void myStackFree(MyStack* obj) {QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj); }

    4.3 用棧實(shí)現(xiàn)隊(duì)列

    來(lái)源:Leetcode。OJ鏈接
    請(qǐng)你僅使用兩個(gè)棧實(shí)現(xiàn)先入先出隊(duì)列。隊(duì)列應(yīng)當(dāng)支持一般隊(duì)列支持的所有操作(push、pop、peek、empty):

    實(shí)現(xiàn) MyQueue 類:

    void push(int x) 將元素 x 推到隊(duì)列的末尾
    int pop() 從隊(duì)列的開(kāi)頭移除并返回元素
    int peek() 返回隊(duì)列開(kāi)頭的元素
    boolean empty() 如果隊(duì)列為空,返回 true ;否則,返回 false


    解題思路:棧的規(guī)則是先進(jìn)后出,如何利用兩個(gè)棧實(shí)現(xiàn)先進(jìn)先出模擬隊(duì)列?
    不難發(fā)現(xiàn),如果一個(gè)棧只入數(shù)據(jù),另一個(gè)棧從入棧中依次取出棧頂?shù)臄?shù)據(jù)后再出棧,這種出棧的順序正好符合先進(jìn)先出。
    具體地,定義一個(gè)入棧s1,出棧s2,當(dāng)入數(shù)據(jù)全部入到s1中,當(dāng)出數(shù)據(jù)時(shí)判斷s2是否為空,如果為空,開(kāi)始從s1的棧頂取出數(shù)據(jù),每次取出后,pop掉s1中棧頂?shù)臄?shù)據(jù)。
    全部取出放入s2后,再進(jìn)行出棧操作,數(shù)據(jù)的出棧順序就變成了先進(jìn)先出。
    s2的棧頂就可以理解為隊(duì)列的隊(duì)頭,此時(shí)s2棧頂?shù)臄?shù)據(jù)依次出棧(出隊(duì)),就模擬出了隊(duì)列的效果。

    //造輪子 //... //... //把上面實(shí)現(xiàn)的棧原封不動(dòng)的拷貝下來(lái)//創(chuàng)建結(jié)構(gòu)體 typedef struct {Stack s1;Stack s2; } MyQueue;//創(chuàng)建兩個(gè)棧 //s1是入棧 //s2是出棧 MyQueue* myQueueCreate() {MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));InintStack(&obj->s1);InintStack(&obj->s2);return obj; } //入棧的數(shù)據(jù)直接存放到s1中 void myQueuePush(MyQueue* obj, int x) {PushStack(&obj->s1, x); } //判斷入棧是否為空 //如果為空則把入棧的數(shù)據(jù)全部取出放入出棧中 //這樣才符合隊(duì)列的先進(jìn)先出 void PushToPop(Stack* push, Stack* pop) {if(StackEmpty(pop)){while(!StackEmpty(push)){PushStack(pop, StackTop(push));PopStack(push);}} } //出隊(duì)并刪除隊(duì)頭元素 //(棧的規(guī)則是先進(jìn)后出,把入棧的順序反過(guò)來(lái)就變成了先進(jìn)先出,也就是隊(duì)列的規(guī)則) int myQueuePop(MyQueue* obj) {PushToPop(&obj->s1, &obj->s2);int top = StackTop(&obj->s2);PopStack(&obj->s2);return top; } //出隊(duì) int myQueuePeek(MyQueue* obj) {PushToPop(&obj->s1, &obj->s2);return StackTop(&obj->s2); } //兩個(gè)棧都不為空 bool myQueueEmpty(MyQueue* obj) {return StackSize(&obj->s1) == 0 && StackSize(&obj->s2) == 0; } //釋放棧 void myQueueFree(MyQueue* obj) {free((&obj->s1)->stack);free((&obj->s2)->stack);free(obj); }

    4.4 設(shè)計(jì)循環(huán)隊(duì)列

    來(lái)源:Leetcode。OJ鏈接

    設(shè)計(jì)你的循環(huán)隊(duì)列實(shí)現(xiàn)。 循環(huán)隊(duì)列是一種線性數(shù)據(jù)結(jié)構(gòu),其操作表現(xiàn)基于 FIFO(先進(jìn)先出)原則并且隊(duì)尾被連接在隊(duì)首之后以形成一個(gè)循環(huán)。它也被稱為“環(huán)形緩沖器”。

    循環(huán)隊(duì)列的一個(gè)好處是我們可以利用這個(gè)隊(duì)列之前用過(guò)的空間。在一個(gè)普通隊(duì)列里,一旦一個(gè)隊(duì)列滿了,我們就不能插入下一個(gè)元素,即使在隊(duì)列前面仍有空間。但是使用循環(huán)隊(duì)列,我們能使用這些空間去存儲(chǔ)新的值。

    你的實(shí)現(xiàn)應(yīng)該支持如下操作:

    • MyCircularQueue(k): 構(gòu)造器,設(shè)置隊(duì)列長(zhǎng)度為 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ì)列可以使用數(shù)組實(shí)現(xiàn),也可以使用循環(huán)鏈表實(shí)現(xiàn)。

    環(huán)形隊(duì)列第一個(gè)比較棘手的問(wèn)題是如何判空以及如何判滿,有兩種方法:
    1、添加一個(gè)size變量用來(lái)記錄數(shù)據(jù)個(gè)數(shù)
    2、額外增加一個(gè)空間,滿的時(shí)候永遠(yuǎn)留一個(gè)位置。比如說(shuō)有效數(shù)據(jù)個(gè)數(shù)為4,那么開(kāi)空間時(shí)開(kāi)辟5個(gè)數(shù)據(jù)的空間,在判斷時(shí)會(huì)比較方便。

    如上圖,到這里其實(shí)可以發(fā)現(xiàn)使用鏈表來(lái)實(shí)現(xiàn)的話會(huì)有一個(gè)不好的地方,不方便取出尾結(jié)點(diǎn)的數(shù)據(jù),因?yàn)閞ear那地方并不是有效數(shù)據(jù)的位置,除非再定義一個(gè)指針,指向尾結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn),但是實(shí)現(xiàn)起來(lái)就比較麻煩了。但是使用數(shù)組就比較方便訪問(wèn)了,因?yàn)榭梢灾С窒聵?biāo)快速訪問(wèn),無(wú)需遍歷,rear-1就可以取出最后一個(gè)位置的數(shù)據(jù),因此這題選擇數(shù)組來(lái)實(shí)現(xiàn)。

    如果選擇數(shù)組,還有一個(gè)小問(wèn)題是判滿情況,判滿的表達(dá)式為rear+1 == front,如果下標(biāo)rear+1越界了如何處理?

    可以使用取模運(yùn)算來(lái)巧妙地解決這個(gè)問(wèn)題,因?yàn)樵摂?shù)組的實(shí)際大小為5(下標(biāo)訪問(wèn)范圍為0~4),而實(shí)際有效的范圍為4(下標(biāo)訪問(wèn)范圍為0~3),因此,當(dāng)rear的下標(biāo)為4的時(shí)候,說(shuō)明到了數(shù)組的最后一個(gè)位置,此時(shí)令(rear+1) %= 5,讓其回到數(shù)組最開(kāi)頭的位置,這也就是循環(huán)數(shù)組一個(gè)最基本的做法(到達(dá)最后一個(gè)位置時(shí)再回到最開(kāi)始的位置),這時(shí)判斷rear == front。

    搞清楚這個(gè)之后,實(shí)現(xiàn)循環(huán)隊(duì)列就比較簡(jiǎn)單了.

    typedef struct {int* arr;int front;int rear;int arrSize; } MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多增加一個(gè)位置obj->arr = (int*)malloc(sizeof(int)*(k+1));obj->front = obj->rear = 0;obj->arrSize = k+1;return obj; } //頭尾相等則為空 bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->rear; } //尾+1等于頭則為滿 bool myCircularQueueIsFull(MyCircularQueue* obj) {return ((obj->rear+1) % obj->arrSize) == obj->front; } //插入數(shù)據(jù) bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj)){return 0;}obj->arr[obj->rear] = value;obj->rear++;//++后如果==arrSize,讓其%arrSize回到0//小于%后值不變obj->rear %= obj->arrSize; return 1; } //刪除數(shù)據(jù) bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return 0;}//同樣的道理,如果++等于arrSizeobj->front++;obj->front %= obj->arrSize; return 1; } //返回隊(duì)頭數(shù)據(jù) int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->arr[obj->front]; } //返回隊(duì)尾數(shù)據(jù) int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->arr[(obj->rear-1) % obj->N]; }void myCircularQueueFree(MyCircularQueue* obj) {free(obj->arr);free(obj); }

    有點(diǎn)難哦

    總結(jié)

    以上是生活随笔為你收集整理的我幼儿园的弟看了都直呼简单的【栈和队列】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。