數據結構之隊列詳解(包含例題)

一、隊列的概念

隊列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。

二、模擬實現順序隊列

我們可以用單鏈表模擬實現順序隊列。

隊列采用的FIFO(first in first out),新元素(等待進入隊列的元素)總是被插入到鏈表的尾部(對應單鏈表的尾插),而讀取的時候總是從鏈表的頭部開始讀取。每次讀取一個元素,釋放一個元素(對應單鏈表的頭刪)。

對應的接口

注意又提供一種避免使用二級指針的方法,創建一個結構體變量,里面存儲結點,當我們想要改變結構體里面的值,我們就用一級指針即可。

typedef int QDataType;
typedef struct QueueNode
{//用單鏈表模擬實現隊列struct QueueNode* next;QDataType data;
}QNode;//新的避免二級指針的結構體
typedef struct Queue
{QNode* head;QNode* tail;int sz;
}Que;void QueueInit(Que* pq);
void QueueDestory(Que* pq);
void QueuePush(Que* pq, QDataType x);
void QueeuPop(Que* pq);
QDataType QueueFront(Que* pq);
QDataType QueueBack(Que* pq);
bool QueueEmpty(Que* pq);
int QueueSize(Que* pq);

隊列的初始化:

void QueueInit(Que* pq)
{assert(pq);pq->sz = 0;pq->head = pq->tail = NULL;
}

隊列的銷毀

注意free過后,也要指向空

void QueueDestroy(Que* pq)
{assert(pq);while (pq->sz > 0){QNode* cur = pq->head->next;free(pq->head);pq->head = cur;pq->sz--;}pq->tail = pq->head = NULL;
}

隊列的插入數據

也就是單鏈表的尾插,同時也要注意當隊列為空時的特殊情況。

void QueuePush(Que* pq,QDataType x)
{//類似于尾插assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror(malloc);exit(-1);}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = pq->tail = newnode;pq->sz++;}else{pq->sz++;pq->tail->next = newnode;pq->tail = newnode;}
}

隊列的刪除數據

也就是單鏈表的頭刪,同時也要注意只剩下一個結點刪除后,尾結點指向空的情況


void QueeuPop(Que* pq)
{assert(pq);assert(pq->sz > 0);//頭刪//單獨判斷只剩下一個結點,頭刪后tail是野指針的情況if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;pq->sz--;}else{QNode* cur = pq->head;pq->head = pq->head->next;free(cur);pq->sz--;}}

返回隊列頭數據

QDataType QueueFront(Que* pq)
{assert(pq);//assert(pq->head);assert(!QueueEmpty(pq));return pq->head->data;
}

返回隊列尾數據

QDataType QueueBack(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}

判斷隊列是否為空

bool QueueEmpty(Que* pq)
{assert(pq);return pq->head == NULL;
}

返回隊列的數據個數

int QueueSize(Que* pq)
{assert(pq);//assert(pq->head);return pq->sz;
}

三、模擬實現循環隊列

622. 設計循環隊列 - 力扣(LeetCode)

這實際上是把隊列空間想象成一個環形空間,環形空間中的存儲單元循環使用,用這種方法管理的隊列也就稱為循環隊列。

注意本題結構較為復雜,必須要畫圖進行解決,這樣就容易考慮到特殊情況,不容易出錯。

本題用數組實現較為簡單,如果用單鏈表實現,那么rear尾結點的前一個不好尋找。

那數組如何實現循環呢?

數組實現循環并不像單鏈表那樣有一個next指針指向頭結點,如果已經走向尾部,可以直接讓頭部的值等于尾部想要的值。

//如何用數組實現循環?
typedef struct {int* a;int front;int rear;int num;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* cur = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//用k+1個數組空間,便于判斷空和滿的情況。cur->a = (int*)malloc(sizeof(int)*(k+1));cur->front = 0;cur->rear = 0;cur->num = k;return cur;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {if(obj->front == obj->rear)return true;elsereturn false;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {//兩種情況都要考慮到!if(obj->front-obj->rear == 1 || obj->rear-obj->front == obj->num)return true;elsereturn false;
}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//先判斷是否已經滿if(myCircularQueueIsFull(obj) == true)return false;//假設rear在隊列的尾部if(obj->rear == obj->num){obj->a[obj->rear] = value;obj->rear = 0;}else{obj->a[obj->rear] = value;obj->rear++;}//obj->a[obj->rear] = value;//obj->rear++;//obj->rear %= (obj->num+1);return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {//先判斷是否已經空了if(myCircularQueueIsEmpty(obj) == true){return false;}//假設front在隊列的尾部if(obj->front == obj->num)obj->front = 0;elseobj->front++;//++obj->front;//obj->front %= (obj->num+1);return true;
}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj) == true)return -1;elsereturn obj->a[obj->front];
}int myCircularQueueRear(MyCircularQueue* obj) {//注意隊尾的rear比數據提前一位數,所以是rear-1//但要考慮rear-1的情況if(myCircularQueueIsEmpty(obj) == true)return -1;if(obj->rear == 0){//需要再創建一個臨時變量,不能改變rear的值int tmp = obj->num;return obj->a[tmp];}// else//     return  obj->a[(obj->rear+obj->num)%(obj->num+1)];return obj->a[obj->rear-1];
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);
}

四、用隊列實現棧

225. 用隊列實現棧 - 力扣(LeetCode)

本題要求用兩個隊列實現棧,兩個隊列我們就可以互相倒數據,來滿足題目對棧的需求

思路:

入隊列:

入不為空的隊列

出隊列:

利用隊列的性質將前n-1個數據放入另一個空的隊列中,刪除剩下一個數據,這樣就完成棧的pop操作

代碼:

typedef struct {Que q1;Que q2;
} MyStack;MyStack* myStackCreate() {MyStack* cur = (MyStack*)malloc(sizeof(MyStack));//不能忘記初始化QueueInit(&cur->q1);QueueInit(&cur->q2);return cur;
}void myStackPush(MyStack* obj, int x) {//push到不為空的的隊列中if(!QueueEmpty(&obj->q1)){QueuePush(&obj->q1,x);}else{QueuePush(&obj->q2,x);}
}int myStackPop(MyStack* obj) {//先假設q1不為空,q2為空Que* empty = &obj->q1;Que* nonEmpty = &obj->q2;if(!QueueEmpty(&obj->q1)){//如果假設失敗,相反empty = &obj->q2;nonEmpty = &obj->q1;}while(QueueSize(nonEmpty)>1){//開始用函數進行捯數據//從前往后的順序是根據隊列pop的順序定的QueuePush(empty,QueueFront(nonEmpty));QueuePop(nonEmpty);}int top = QueueBack(nonEmpty);QueuePop(nonEmpty);return top;
}int myStackTop(MyStack* obj) {Que* empty = &obj->q1;Que* nonEmpty = &obj->q2;if(!QueueEmpty(&obj->q1)){//如果假設失敗,相反empty = &obj->q2;nonEmpty = &obj->q1;}return QueueBack(nonEmpty);
}bool myStackEmpty(MyStack* obj) {//判斷兩個隊列return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}void myStackFree(MyStack* obj) {//先對兩個隊列中的鏈表進行freeQueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);
}

五、用棧實現隊列

232. 用棧實現隊列 - 力扣(LeetCode)

題目描述:

請你僅使用兩個棧實現先入先出隊列。隊列應當支持一般隊列支持的所有操作(pushpoppeekempty):

思路:

本題與上一題用隊列實現棧有所差別,可以直接區分push棧和pop棧,如果pop棧為空,就將push棧全部捯到pop棧

代碼:

typedef struct 
{ST push;ST pop;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* cur = (MyQueue*)malloc(sizeof(MyQueue));SLInit(&cur->push);SLInit(&cur->pop);return cur;
}void myQueuePush(MyQueue* obj, int x) {STPush(&obj->push,x);
}int myQueuePop(MyQueue* obj) {int ret = myQueuePeek(obj);STPop(&obj->pop);return ret;
}int myQueuePeek(MyQueue* obj) {//出棧只能從后往前出//如果pop棧為空,就將push棧全部捯到pop棧!if(STEmpty(&obj->pop)){while(!STEmpty(&obj->push)){STPush(&obj->pop,STTop(&obj->push));STPop(&obj->push);}}int ret = STTop(&obj->pop);return ret;
}bool myQueueEmpty(MyQueue* obj) {//用函數求解return STEmpty(&obj->push) && STEmpty(&obj->pop);
}void myQueueFree(MyQueue* obj) {SLDestroy(&obj->pop);SLDestroy(&obj->push);free(obj);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41952.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41952.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41952.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Windows 常用工具系列 5 -- Selenium IDE的使用方法 】

文章目錄 Selenium 介紹Selenium IDE 介紹 Selenium IDE安裝Chrome 瀏覽器安裝Selenium IDE使用 Selenium 介紹 Selenium是一個用于Web應用程序測試的工具。Selenium測試直接運行在瀏覽器中,就像真正的用戶在操作一樣。 Selenium家庭成員有三個,分別是S…

Ubuntu 20.04 與 ROS noetic安裝 gtsam 編譯 LIO-SAM 的適配版本

Ubuntu 20.04 基于 ROS noetic安裝 gtsam, 編譯 LIO-SAM 的適配版本 摘要安裝GTSAM(ros-noetic-gtsam版本)編譯LIO-SAM的適配版本 摘要 本文簡介在 Ubuntu 20.04 下以 ROS noetic 為基礎安裝 GTSAM 并成功編譯 LIO-SAM 的適配版本。 安裝GTSAM(ros-noetic-gtsam版…

騰訊云國際站代充-阿里云ECS怎么一鍵遷移到騰訊云cvm?

今天主要來介紹一下如何通過阿里云國際ECS控制臺一鍵遷移至騰訊云國際CVM。騰訊云國際站云服務器CVM提供全面廣泛的服務內容。無-需-綁-定PayPal,代-充-值騰訊云國際站、阿里云國際站、AWS亞馬遜云、GCP谷歌云,官方授權經銷商!靠譜&#xff0…

視頻匯聚集中存儲EasyCVR平臺調用iframe地址視頻無法播放,該如何解決?

安防監控視頻匯聚平臺EasyCVR基于云邊端一體化架構,具有強大的數據接入、處理及分發能力,可提供視頻監控直播、云端錄像、視頻云存儲、視頻集中存儲、視頻存儲磁盤陣列、錄像檢索與回看、智能告警、平臺級聯、云臺控制、語音對講、AI算法中臺智能分析無縫…

【SpringBoot】中的ApplicationRunner接口 和 CommandLineRunner接口

1. ApplicationRunner接口 用法: 類型: 接口 方法: 只定義了一個run方法 使用場景: springBoot項目啟動時,若想在啟動之后直接執行某一段代碼,就可以用 ApplicationRunner這個接口,并實現接口…

vue3+elementUI-plus實現select下拉框的虛擬滾動

網上查了幾個方案,要不就是不兼容,要不就是不支持vue3, 最終找到一個合適的,并且已上線使用,需要修改一下樣式: 代碼如下: main.js里引用 import vue3-virtual-scroller/dist/vue3-virtual-scroller.css; …

xollam勒索病毒數據恢復|金蝶、用友、管家婆、OA、速達、ERP等軟件數據庫恢復

引言: 數字時代的繁榮與便捷,也孕育著各種網絡安全威脅。其中,.xollam勒索病毒以其毒害性和隱蔽性引發了廣泛關注。本文91數據恢復將為您深入解析.xollam勒索病毒的威脅,探討解密方法,同時分享預防.xollam勒索病毒的關…

Python入門教程23:math模塊的用法

**math是Python 的一個內置模塊,它提供了許多數學函數和常量,用于進行數學計算。**以下是一些常用的math模塊中的函數和常量: math.pi:圓周率π的近似值,約等于3.14159。 math.e:自然對數的底數e的近似值…

【Tomcat】(Tomcat 下載Tomcat 啟動Tomcat 簡單部署 基于Tomcat進行網站后端開發)

文章目錄 Tomcat下載Tomcat啟動Tomcat簡單部署 基于Tomcat進行網站后端開發 Tomcat Tomcat 是一個 HTTP 服務器.HTTP 協議就是 HTTP 客戶端和 HTTP 服務器之間的交互數據的格式. HTTP 服務器我們可以通過 Java Socket 來實現. 而 Tomcat 就是基于 Java 實現的一個開源免費,也是…

Python爬蟲:如何使用Python爬取網站數據

更新:2023-08-13 15:30 想要獲取網站的數據?使用Python爬蟲是一個絕佳的選擇。Python爬蟲是通過自動化程序來提取互聯網上的信息。本文章將會詳細介紹Python爬蟲的相關技術。 一、網絡協議和請求 在使用Python爬蟲之前,我們需要理解網絡協…

Synopsys EDA數字設計與仿真

搭建EDA環境 參考如下博文安裝Synopsys EDA開發工具 https://blog.csdn.net/tugouxp/article/details/132255002?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22132255002%22%2C%22source%22%3A%22tugouxp%22%7D Synopsys ED…

【Git】本地搭建Gitee、Github環境

本地 (Local) 1、使用命令生成公鑰(pub文件) 1. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "github_id_rsa" 2. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "gitee_id_rsa" …

配置pyqt5開發環境

安裝庫 pip install pyqt5 -i https://mirrors.aliuyun.com/pypi/simple pip install pyqt5-tools -i https://mirrors.aliuyun.com/pypi/simple pip install PyQt5designer -i https://mirrors.aliuyun.com/pypi/simple配置External Tools Name:QtDesigner Program:C:\Anaco…

常見的 JavaScript 框架比較

以下是10種常見的JavaScript框架的比較: React:是由Facebook開發和維護的開源JavaScript庫,用于構建用戶界面。它允許你使用組件來構建復雜的UI,并專注于每個組件的內部邏輯,而不必擔心管理整個應用程序的狀態。WebBu…

使用路由器更改設備IP_跨網段連接PLC

在一些設備IP已經固定,但是需要采集此設備的數據,需要用到跨網段采集 1、將路由器WAN(外網撥號口)設置為靜態IP 2、設置DMZ主機,把DMZ主機地址設置成跨網段的PLC地址 DMZ主機 基本信息. DMZ (Demilitarized Zone)即俗稱的非軍事區&#xff0…

牛客網華為OD前端崗位,面試題庫練習記錄01

題目一 質數因子 功能:輸入一個正整數,按照從小到大的順序輸出它的所有質因子(重復的也要列舉)(如180的質因子為2 2 3 3 5 ) JavaScript Node ACM模式 const rl require("readline").createInterface({ i…

IPv4分組

4.3.1 IPv4分組 IP協議定義數據傳送的基本單元——IP分組及其確切的數據格式 1. IPv4分組的格式 IPv4分組由首部和數據部分(TCP、UDP段)組成,其中首部分為固定部分(20字節)和可選字段(長度可變&#xff0…

1AE4 的魔改混合放大電路

先上電路圖: 最新的1AE4的電路,目標依舊是極致的音效。 因此,為了將1AE4的潛力榨干,采用了一些完全不同的思路: 1)原有的屏極接地,因為是一個殼子,所以能起到很好的屏蔽作用&#…

651頁23萬字智慧教育大數據信息化頂層設計及建設方案WORD

導讀:原文《651頁23萬字智慧教育大數據信息化頂層設計及建設方案WORD》(獲取來源見文尾),本文精選其中精華及架構部分,邏輯清晰、內容完整,為快速形成售前方案提供參考。 目錄 一、 方案背景 1.1 以教育…

微信開發之一鍵獲取好友詳情的技術實現

簡要描述: 獲取聯系人信息 請求URL: http://域名地址/getContact 請求方式: POST 請求頭Headers: Content-Type:application/jsonAuthorization:login接口返回 參數: 參數名必選類型說…