【LeetCode刷題之路】622.設計循環隊列

在這里插入圖片描述

LeetCode刷題記錄
  • 🌐 我的博客主頁:iiiiiankor
  • 🎯 如果你覺得我的內容對你有幫助,不妨點個贊👍、留個評論?,或者收藏?,讓我們一起進步!
  • 📝 專欄系列:LeetCode 刷題日志
  • 🌱 文章內容來自我的學習與實踐經驗,如果你有任何想法或問題,歡迎隨時在評論區交流討論。讓我們一起探索更多的可能!🚀

文章目錄

  • 🚀LeetCode622.設計循環隊列
    • 一、🌟題目描述🌟
    • 二、🎨分析🎨
      • 鏈表實現分析
    • 三、💥題解💥
      • 定義隊列結構
      • Create(創建隊列)
      • 判斷是否為空
      • 判斷是不是滿了
      • 獲取隊頭元素
      • 獲取隊尾元素
      • push接口
      • pop接口
      • 銷毀
      • ??總代碼??
  • 💥💥最后貼一個題 💥💥

🚀LeetCode622.設計循環隊列

鏈接:LeetCode622.設計循環隊列

一、🌟題目描述🌟

在這里插入圖片描述

二、🎨分析🎨

  • 題目理解:
    這是讓我們實現的是一個 大小固定的循環隊列
    正常的大小固定的隊列如果滿了就不能插入了
    而這里所說的循環隊列 是隊尾和隊頭連在一起的
    所以我們首先想到的就是 利用鏈表實現循環隊列

鏈表實現分析

如下圖:
剛開始head和tail都指向一個頭!
在這里插入圖片描述
這種結構下

  • 插入數據只需要把數據放到tail節點,然后tail向后走
    如圖:push 1 2 3
    在這里插入圖片描述
  • pop數據 只需要讓head走向下一個,數據清除或者不清楚無所謂,反正可以被替換,
    如圖:pop pop
    在這里插入圖片描述
    注意節點不需要釋放!
    而如果繼續插入數據:push 4 5 6 7
    在這里插入圖片描述
    可以看到此時已經滿了!
    但是,大家看一下我們設計的這個有沒有什么缺陷呢?
    !對! 我們可以看到!隊列什么時候滿呢?
    head==tail的時候滿
    那么什么時候為空呢?
    head==tail的時候為空!
    所以! 這里判斷空和滿是有問題的!

那么解決方法是什么呢?

  1. 給一個size記錄隊列的大小,循環隊列的節點數為k,每一次push的時候size++,pop時size–當head==tail 時,如果size為k說明已經滿了,如果size為0 則說明為空
  2. 給一個flag 剛開始flag為0表示隊列為空,如果head==tail了 flag置為1,表示已經滿了,當再pop的時候,就把flag改成0表示未滿
  3. 比較官方的做法:
    我們直接開辟k+1個鏈表節點,其中有一個節點不存儲有效數據
    判滿的條件就是 tail的下一個為head

如圖:push 4 5 6 7
只能插入4 5 6 到7的時候 tail->next==head 所以已經滿了,無法插入!
在這里插入圖片描述
通常來說 結構就是這樣的:
在這里插入圖片描述

但是這時候這個隊列還有別的問題嗎?
我們要實現 push pop 判空 判滿 獲取隊頭數據 獲取隊尾數據 等等…
我們可以發現,如果想要獲取隊尾數據 是比較麻煩的!!
因為我們的tail是下一個要push的位置而不是真正的隊尾
所以 我們如果想要解決,必須找到tail的前一個

  • 方法1: 雙向鏈表
  • 方法2:記錄尾的同時還要記錄尾的前一個

顯然 都是麻煩事! 所以利用鏈表是不方便實現的

所以我們選擇用數組實現

三、💥題解💥

我們利用數組實現
先簡單分析一下:
在這里插入圖片描述
對于一個數組,我們要實現循環隊列,那么
在這里插入圖片描述
因為隊列是循環的,所以什么時候隊列是滿的呢?
這就和我們鏈表部分分析的一樣了,有三種方法!

  1. flag標識
  2. size記錄隊列大小
  3. 多開辟一個空間 ?

我們采取對數組多開辟一個空間的方法:開辟(k+1)個空間


下面是具體接口實現:
?代碼中都有詳細注釋哦!!?

定義隊列結構

typedef struct {int* a;//動態開辟數組int head;//隊頭int tail;//隊尾int k;//隊的大小,因為后面傳參的時候不會再傳 k 所以我們定義在結構體里面
} MyCircularQueue;

Create(創建隊列)

我們以k=5為例

	首先創建一個隊列結構然后開辟出隊列中大小為`k+1`的數組然后把結構中的head和tail初始化為0

如圖:
在這里插入圖片描述

判斷是否為空

前面我們對鏈表實現的分析的時候
我們已經分析過了
當`head`==`tail`的時候,為空
只是這里的`head`和`tail`變成了下標而不是節點
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//判斷是不是為空 只需要判斷tail是不是等于headreturn obj->head==obj->tail;}

判斷是不是滿了

這里是稍微有點麻煩的

首先我們要知道,判斷滿的條件是tail的下一個等于head
但是這是數組 !not 鏈表
如果是環形鏈表,他會自動實現很自然的循環
但是鏈表不一樣
鏈表會走到一個邊界,所以我們需要考慮tail的下一個是誰?
我們定義一個next來標識下一個
一般的tail的下一個就是tail+1 ,如下圖
在這里插入圖片描述
但是存在特殊情況:如果tail已經是最后一個位置了,那么這時候其實他的下一個就是返回開頭0
在這里插入圖片描述

找到下一個?
1.  定義一個next=tail+1如果tail==k+1那么next就為02.  利用取模我們知道一共有k+1個空間所以下標的返回時 0~ k這時候 next=(tail+1)%(k+1)不管next是不是超過了數組的返回,結果都是正確的

代碼:

bool myCircularQueueIsFull(MyCircularQueue* obj) {//判斷是不是滿了//一般是判斷tail的下一個是不是 head//需要考慮tail的下一個是什么?int next=obj->tail+1;if(next==obj->k+1){next=0;}//next=(obj->tail+1)%(k+1);if(next==obj->head)return true;elsereturn false;
}

獲取隊頭元素

隊頭其實就是`head`
所以只需要訪問數組中的`head`位置處的元素就可以了

但是需要注意:如果隊列為空,返回-1

int myCircularQueueFront(MyCircularQueue* obj) {//如果隊列為空 返回-1if(myCircularQueueIsEmpty(obj)){return -1;}//隊頭就是 headreturn obj->a[obj->head];
}

獲取隊尾元素

在這里插入圖片描述
我們可以看到tail表示的是下一個Push的位置
而如果我們想獲得隊尾元素
應該是獲得tail的前一個元素

所以我們定義一個prev來找到tail的前一個元素

但是也會有特殊情況

在這里插入圖片描述
如果是這種情況,也就是 tail已經折回去了
tail為0 prev應該為5
怎么找到prev呢?
注意 如果我們讓tail+k+1 ,tail就變成了6
這時候tail-1是不是就等于prev了?
tail為0實際上就說明了tail已經走到數組最后一個位置的后一個了


細細剖析理解一下這里:
在這里插入圖片描述
在這里插入圖片描述
而我們再看正確的情況是不是滿足呢?
在這里插入圖片描述
顯然 滿足的!

這樣 我們就有兩種情況控制邊界情況
1. if判斷
2. 利用取模
具體看個人喜歡用那種,小編這里就用第一種啦(比較直觀)
int myCircularQueueRear(MyCircularQueue* obj) {//首先判斷是否為空if(myCircularQueueIsEmpty(obj)){return -1;}//如果不為空//找到tail的前一個int prev=obj->tail-1;if(obj->tail==0)prev=obj->k;return obj->a[prev];
}

push接口

我們開始以k=5為例,即開辟了一個大小為6的數組

在這里插入圖片描述

正常情況下,我們push只需要把tail位置放入元素,然后tail++就可以了
(向后走一步)
如圖 我們把一個空的隊列 push 1 2 3 4
操作過程:在這里插入圖片描述

在這里插入圖片描述

但是會存在特殊情況
如圖:在這里插入圖片描述

這時候怎么push呢?tail已經走到末尾了!

  1. 直接控制:正常走的話tail+1,tail就變成了6
    所以 如果tail==k+1 那么我們讓tail=0就可以了!
  2. 利用取模
    因為數組的總空間就是k+1
    所以如果我們tail等于6了,說明tail應該走到0
    所以讓tail%=(k+1),也就是 6%6==0

還有一個問題就是
什么時候push失敗呢?

當滿的時候會push 失敗!

在這里插入圖片描述
push代碼:

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//首先判斷是不是滿了//如果滿了 push失敗--返回falseif(myCircularQueueIsFull(obj)){return false;}//如果不滿 直接插入就可以了obj->a[obj->tail]=value;//然后tail需要移動!obj->tail++;//如果移動之后tail走到末尾了 tail返回到數組的最開始if(obj->tail==obj->k+1){obj->tail=0;}return true;
}

pop接口

我們來看一個例子
在這里插入圖片描述
如果操作為 pop pop
那么 head就需要往前走兩步,從而實現刪除的效果
在這里插入圖片描述
但是如果繼續pop
操作: pop pop
在這里插入圖片描述
可以看到,此時隊列已經空了!
此時繼續pop就返回false(失敗)

正常情況下pop只需要讓head向后走,就可以了
因為前面的數據可以隨意被覆蓋就相當于被刪了

但是也會有特殊情況,即當head走到邊界
在這里插入圖片描述
此時如果繼續pop head++就變成了6
但是head應該返回到數組的頭部0
所以 解決方法依舊有兩個:

  1. 如果head==k+1
    那么 head變成0
  2. 取模:如果head++之后變成6
    那么head=head%(k+1)

代碼:

bool myCircularQueueDeQueue(MyCircularQueue* obj) {//如果 隊列已經空空了 就返回falseif(myCircularQueueIsEmpty(obj)){return false;}//如果隊列不為空obj->head++;if(obj->head==obj->k+1){obj->head=0;}return true;
}

銷毀

銷毀就很簡單了
只需要把結構銷毀就可以了

注意:銷毀結構之前,需要把結構中malloc的動態數組釋放
否則容易造成內存泄漏!!

void myCircularQueueFree(MyCircularQueue* obj) {//首先釋放數組空間free(obj->a);//然后釋放隊列free(obj);
}

總結:這道題還是比較麻煩的!
很多細節:比如邊界 需要我們考慮全面!
下面是總代碼供參考!

??總代碼??

//使用數組實現typedef struct {int* a;//動態開辟數組int head;//隊頭int tail;//隊尾int k;//隊的大小,因為后面傳參的時候不會再傳k 所以我們定義在結構體里面
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->a=(int*)malloc(sizeof(int)*(k+1));obj->k=k;obj->head=obj->tail=0;return obj;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//判斷是不是為空 只需要判斷tail是不是等于headreturn obj->head==obj->tail;}bool myCircularQueueIsFull(MyCircularQueue* obj) {//判斷是不是滿了//一般是判斷tail的下一個是不是 head//需要考慮tail的下一個是什么?int next=obj->tail+1;if(next==obj->k+1){next=0;}//next=(obj->tail+1)%(k+1);if(next==obj->head)return true;elsereturn false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//首先判斷是不是滿了//如果滿了 push失敗--返回falseif(myCircularQueueIsFull(obj)){return false;}//如果不滿 直接插入就可以了obj->a[obj->tail]=value;//然后tail需要移動!obj->tail++;//如果移動之后tail走到末尾了 tail返回到數組的最開始if(obj->tail==obj->k+1){obj->tail=0;}return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {//如果 隊列已經空空了 就返回falseif(myCircularQueueIsEmpty(obj)){return false;}//如果隊列不為空obj->head++;if(obj->head==obj->k+1){obj->head=0;}return true;
}int myCircularQueueFront(MyCircularQueue* obj) {//如果隊列為空 返回-1if(myCircularQueueIsEmpty(obj)){return -1;}//隊頭就是 headreturn obj->a[obj->head];
}int myCircularQueueRear(MyCircularQueue* obj) {//首先判斷是否為空if(myCircularQueueIsEmpty(obj)){return -1;}//如果不為空//找到tail的前一個int prev=obj->tail-1;if(obj->tail==0)prev=obj->k;return obj->a[prev];
}void myCircularQueueFree(MyCircularQueue* obj) {//首先釋放數組空間free(obj->a);//然后釋放隊列free(obj);
}

💥💥最后貼一個題 💥💥

這個題適合 LeetCode622.循環隊列中的邊界問題相關的
看一下你學廢了嗎

5.現有一循環隊列,其隊頭指針為front,隊尾指針為rear;循環隊列長度為N。
其隊內有效長度為?(假設隊頭不存放數據)
A (rear - front + N) % N + 1
B (rear - front + N) % N
C ear - front) % (N + 1)
D (rear - front + N) % (N - 1)

?感謝閱讀~ ?
??碼字不易,給個贊吧~??

在這里插入圖片描述

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

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

相關文章

Node.js基礎入門

1.Node.js 簡介 Node 是一個讓 JavaScript (獨立)運行在服務端的開發平臺,它讓 JavaScript 成為與PHP、Python、Perl、Ruby 等服務端語言平起平坐的腳本語言。 發布于2009年5月,由Ryan Dahl開發,實質是對Chrome V8引擎進行了封裝。 簡單的說 Node.js 就是運行在服務端的…

#思科模擬器通過服務配置保障無線網絡安全Radius

演示拓撲圖: 搭建拓撲時要注意: 只能連接它的Ethernet接口,不然會不通 MAC地址綁定 要求 :通過配置MAC地址過濾禁止非內部員工連接WiFi 打開無線路由器GUI界面,點開下圖頁面,配置路由器無線網絡MAC地址過…

docker 部署kafka集群

docker run 部署 docker run -d --name zookeeper --restart always -p 2181:2181 wurstmeister/zookeeperdocker run -d --name kafka1 --restart always -p 9094:9092 \-e KAFKA_ADVERTISED_HOST_NAME182.54.14.45 \-e KAFKA_ZOOKEEPER_CONNECT182.54.14.45:2181 \-e KAFKA_…

Qt-chart 畫折線圖(以時間為x軸)

上圖 代碼 #include <iostream> #include <random> #include <qcategoryaxis.h>void MainWindow::testLine() {//1、創建圖表視圖QChartView* view new QChartView(this);//2.創建圖表QChart* chart new QChart();//3.將圖表設置給圖表視圖view->setCh…

C++多線程常用方法

在 C 中&#xff0c;線程相關功能主要通過頭文件提供的類和函數來實現&#xff0c;以下是一些常用的線程接口方法和使用技巧&#xff1a; std::thread類 構造函數&#xff1a; 可以通過傳入可調用對象&#xff08;如函數指針、函數對象、lambda 表達式等&#xff09;來創建一…

up主親測,ToDesk/青椒云/順網云這三款云電腦玩轉AIGC場景

文章目錄 1. 前言2. 云電腦性能分析3. 基礎硬件數據3.1 硬件配置3.2 AI 評測跑分 4. 云電腦 AIGC 上手實測4.1 ToDesk4.1.1 AIGC 技術集成情況4.1.2 界面及功能4.1.3 項目部署4.1.4 黑神話悟空 AI 換臉4.1.6 AIGC 文生圖體驗 4.2 青椒云4.2.1 AIGC 技術集成情況4.2.2 界面及功能…

C++(十八)

前言&#xff1a; 本文依據上一篇&#xff0c;繼續對C中的函數進行學習。 一&#xff0c;內聯函數。 再執行函數代碼時&#xff0c;比不使用函數花費了更多時間&#xff0c;因為總結步驟&#xff0c;傳遞參數和返回值都很花費時間。 因此&#xff0c;在調試小型函數時&…

功能篇:JAVA后端實現跨域配置

在Java后端實現跨域配置&#xff08;CORS&#xff0c;Cross-Origin Resource Sharing&#xff09;有多種方法&#xff0c;具體取決于你使用的框架。如果你使用的是Spring Boot或Spring MVC&#xff0c;可以通過以下幾種方式來配置CORS。 ### 方法一&#xff1a;全局配置 對于所…

數獨游戲app制作拆解(之一)——功能介紹

android studio版本&#xff1a;2023.3.1 例程名稱&#xff1a;shudu666 前陣子作了一個EXCEL版的數獨&#xff0c;再早之前就想作這個數獨app,但一直沒動手&#xff0c;一方面懶&#xff0c;另一方面我把自己繞到坑里了&#xff0c;之前做的是一解數獨的app,那個是有點難&am…

Spring注解篇:@Configuration詳解

前言 在Spring框架中&#xff0c;Configuration注解是實現Java配置的核心。它允許開發者以編程的方式定義Bean的創建過程&#xff0c;而不是使用XML文件。這種基于注解的配置方式&#xff0c;不僅簡化了配置的復雜性&#xff0c;還提高了代碼的可讀性和可維護性。 摘要 本文…

通過一個例子學習回溯算法:從方法論到實際應用

回溯算法&#xff1a;從方法論到實際應用 回溯算法&#xff08;Backtracking&#xff09;是一種通過窮舉法尋找問題所有解的算法&#xff0c;它的核心思想是逐步構建解空間樹&#xff0c;在每個步驟中判斷當前解是否合法。如果不合法&#xff0c;就“回溯”到上一步&#xff0…

Python隨機抽取Excel數據并在處理后整合為一個文件

本文介紹基于Python語言&#xff0c;針對一個文件夾下大量的Excel表格文件&#xff0c;基于其中每一個文件&#xff0c;隨機從其中選取一部分數據&#xff0c;并將全部文件中隨機獲取的數據合并為一個新的Excel表格文件的方法。 首先&#xff0c;我們來明確一下本文的具體需求。…

構建樹莓派溫濕度監測系統:從硬件到軟件的完整指南

?作者簡介&#xff1a;2022年博客新星 第八。熱愛國學的Java后端開發者&#xff0c;修心和技術同步精進。 &#x1f34e;個人主頁&#xff1a;Java Fans的博客 &#x1f34a;個人信條&#xff1a;不遷怒&#xff0c;不貳過。小知識&#xff0c;大智慧。 &#x1f49e;當前專欄…

28. Three.js案例-創建圓角矩形并進行拉伸

28. Three.js案例-創建圓角矩形并進行拉伸 實現效果 知識點 WebGLRenderer (WebGL渲染器) WebGLRenderer 是 Three.js 中用于渲染 3D 場景的主要渲染器。 構造器 WebGLRenderer( parameters : Object ) 參數類型描述parametersObject渲染器的配置參數&#xff0c;可選。 …

開源Java快速自測工具,可以調用系統內任意一個方法

java快速測試框架&#xff0c;可以調到系統內任意一個方法&#xff0c;告別寫單測和controller的困擾。 開源地址&#xff1a;https://gitee.com/missyouch/Easy-JTest 我們在開發時很多時候想要測試下自己的代碼&#xff0c;特別是service層或者是更底層的代碼&#xff0c;就…

004 QT常用控件Qwidget_上

文章目錄 前言控件概述QWidgetenable屬性geometry屬性windowTitle屬性windowlcon屬性 小結 前言 本文將會向你介紹常用的Qwidget屬性 控件概述 Widget 是 Qt 中的核心概念. 英文原義是 “?部件”, 我們此處把它翻譯為 “控件” . 控件是構成?個圖形化界面的基本要素. QWi…

Android 好的開源庫

1. 權限請求框架 GitHub - getActivity/XXPermissions: Android 權限請求框架&#xff0c;已適配 Android 14 2. 下載框架 GitHub - lingochamp/okdownload: A Reliable, Flexible, Fast and Powerful download engine.

Flash語音芯片相比OTP語音芯片的優勢

Flash語音芯片和OTP語音芯片是兩種常見的語音解決方案&#xff0c;在各自的應用領域中發揮著重要作用。本文?將介紹Flash語音芯片相比OTP(One-Time Programmable)語音芯片的顯著優勢?。 1?.可重復擦寫?&#xff1a;Flash語音芯片的最大特點是支持多次編程和擦除&#xff0c…

Android命令行工具--dumpsys

dumpsys 是一種在 Android 設備上運行的工具&#xff0c;可提供有關系統服務的信息。可以使用 Android 調試橋 (adb) 從命令行調用 dumpsys&#xff0c;獲取在連接的設備上運行的所有系統服務的診斷輸出。 此輸出通常比您想要的更詳細&#xff0c;因此請使用此頁面上的命令行選…

【深度學習】深刻理解Swin Transformer

Swin Transformer 是一種基于 Transformer 的視覺模型&#xff0c;由 Microsoft 研究團隊提出&#xff0c;旨在解決傳統 Transformer 模型在計算機視覺任務中的高計算復雜度問題。其全稱是 Shifted Window Transformer&#xff0c;通過引入分層架構和滑動窗口機制&#xff0c;S…