JavaDS —— 棧 Stack 和 隊列 Queue

棧的概念

棧是一種先進后出的線性表,只允許在固定的一端進行插入和刪除操作。
進行插入和刪除操作的一端被稱為棧頂,另一端被稱為棧底

棧的插入操作叫做進棧/壓棧/入棧
棧的刪除操作叫做出棧

在這里插入圖片描述
現實生活中棧的例子:
在這里插入圖片描述

棧的模擬實現

下面是Java集合類給我們提供的棧的方法:

在這里插入圖片描述

模擬實現順序棧

我們通過數組來模擬實現棧。

構建數組棧

我們需要兩個成員變量,一個是數組,另一個是記錄當前的數據個數。

    public int[] elem;public int usedSize;public MyStack() {elem = new int[5];}

push

要考慮擴容問題

    private boolean isFull() {if(usedSize == elem.length) {return true;}return false;}private void grow() {elem = Arrays.copyOf(elem,2*elem.length);}public void push(int val) {if(isFull()) {grow();}elem[usedSize++] = val;}

isEmpty

判斷棧是否為空:

    public boolean isEmpty() {return usedSize == 0;}

pop

設置自定義異常:

public class PopException extends RuntimeException{public PopException() {super();}public PopException(String message) {super(message);}
}

刪除棧頂的同時,還會返回刪除的元素

    private void checkPop() throws PopException{if(isEmpty()) {//拋異常throw new PopException("棧已空,無法刪除!!!");}}public int pop() {try {checkPop();int ret = elem[usedSize-1];usedSize--;return ret;} catch (PopException e) {e.printStackTrace();}return -1;}

peek

獲取棧頂元素 但是不刪除

    public int peek() {try {checkPop();return elem[usedSize-1];} catch (PopException e) {e.printStackTrace();}return -1;}

鏈式棧

鏈式棧顧名思義就是利用鏈表來保存棧

假設使用單鏈表制作鏈式棧,建議使用頭插和頭刪法來進行push和pop操作,peak直接把頭節點的值獲取即可,這樣時間復雜度可以為O(1);但是如果你使用尾插和尾刪就是以尾節點的位置作為棧頂,在push,pop 和 peak 的時候,時間復雜度為O(N)

假設使用雙向無頭循環鏈表,無論是選擇頭插頭刪還是尾插尾刪作為push與pop,時間復雜度都是O(1)

這里就不演示鏈式棧的代碼。

Stack 的使用

在這里插入圖片描述
push 入棧;pop 出棧;peak 獲取棧頂元素;empty 是否為空;size 這個獲取有效元素的方法是在Vector 中的,search 找到某元素距離棧頂元素的距離多少(棧頂元素記為1,然后一直到目標元素)

棧、虛擬機棧、棧幀有什么區別呢?

棧是我們的數據結構的其中一種形式,虛擬機棧是JVM虛擬機的一塊內存,棧幀是運行一個方法或者函數的時候計算機給它開辟的內存。

隊列的概念

隊列:只允許在一端進行插入數據操作,在另一端進行刪除數據操作的特殊線性表,隊列具有先進先出FIFO(First In First Out) 入隊列:進行插入操作的一端稱為隊尾(Tail/Rear) 出隊列:進行刪除操作的一端稱為隊頭(Head/Front)

隊列類似我們生活中的排隊。

在這里插入圖片描述

隊列的模擬實現

在這里插入圖片描述
上面是Java集合類給我們提供的隊列的方法,其中add和offer都是入隊操作,poll 和 remove 都是出隊操作,element 和 peek 都是獲取隊列頭部的元素。

它們主要的區別是會不會拋異常~~ 下面有詳細的介紹:

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述


鏈式隊列

這里我們將使用數組來模擬實現隊列,并且這里只實現下圖所示的方法:
在這里插入圖片描述

size 和 isEmpty 是隊列繼承的方法,并且隊列沒有重寫這兩個方法,所以上面的IDEA直接看隊列的Structure 是看不到的。


假設我們使用單鏈表為基礎,該怎么實現隊列?
假設入隊采用尾插,那要出隊即使用頭刪即可
出隊列使用單鏈表的頭刪即可,時間復雜度為O(1)
入隊列使用尾插,一般情況下,單鏈表實現尾插首先要找到尾,然后才是開始插入,這時候時間復雜度就尾O(N),不是最優解,我們可以加一個尾指針保存好尾節點,這樣就方便我們快速進行尾插操作。

假設入隊使用頭插,那出隊的時候就需要使用尾刪
這時候就不好弄了,即使你有尾指針在進行尾刪的時候還是需要遍歷鏈表找到尾節點的前一個結點才能完成尾刪,這時候你可能會認為再定義一個指針,這就很麻煩了。

所以單鏈表構建隊列的話,限制條件有點大,但是使用上一片文章的雙向鏈表(無頭雙向循環鏈表 LinkedList) ,就可以隨意選取一端作為入隊,另一端作為出隊。

這里我們入隊采用尾插,出隊采用頭刪:

public class MyQueue {public static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;//入隊public boolean offer(int data) {ListNode node = new ListNode(data);if(isEmpty()) {last = head = node;} else {last.next = node;node.prev = last;last = node;}return true;}public boolean isEmpty() {return head == null;}//出隊public int poll() {if(isEmpty()) {return -1;}int ret = head.val;if(head.next != null) {head.next.prev = null;}head = head.next;return ret;}//求結點個數public int size() {ListNode cur = head;int count = 0;while(cur != null) {count++;cur = cur.next;}return count;}//獲取隊頭元素public int peek() {if(isEmpty()) {return -1;}return head.val;}
}

這里要注意出隊的代碼,如果只有一個結點的情況下,你進行刪除后就沒有結點了,head.next.prev = null 這行代碼就會發生報錯。

順序隊列

順序隊列我們采用數組來實現隊列,這時候我們就要思考一個問題,在不斷的出隊入隊的情況下怎么保證空間盡可能地利用起來?
假設數組的數據已滿裝滿的情況下,我們一直出隊直到數組變空的話,怎么利用起來前面的空間?

在這里插入圖片描述

循環隊列

這時候我們就需要使用循環隊列讓隊列的空間有效的利用起來。

法1 :定義一個成員變量,usedSize 記錄使用了多少的空間
法2 : 定義一個標記符,記錄空間是否已滿
法3 :浪費一個空間,通過數學公式判斷隊列是否已滿

在這里插入圖片描述
一般情況下,我們會認為這就是隊列空和滿的兩種狀態,但是這兩種狀態都是 front == near,怎么辦?
根據法1,我們可以記錄使用了多少空間的usedSize 來判斷隊列是否已滿,即 usedSize = 數組的長度即可認為隊列已滿
根據法2,我們使用標記符,首先 將標記符記為 -1,認為隊列沒滿,當front 與near 再次相遇時,標記符乘 -1 變為1 ,判斷 隊列 已滿,如果下一個操作時出隊,那標記符再自乘 -1變回 -1 ,當front 與 rear 再次相遇時標記符自乘 -1 變為1 表示隊列已滿,以此類推,這里大家可以自由發揮。


第三個方法是利用隊列自身來進行判斷,當 rear 的下一個就是 front 的時候(即 ( rear + 1 ) % 數組長度 == front),就判斷隊列已滿,這需要我們浪費隊列的一個空間。
在這里插入圖片描述


如何讓rear 和 front 循環起來呢?即rear 的下標該如何制定呢?
這里有一個公式,當 rear 要 自增的時候,新的 rear = ( rear + 1 ) % 數組長度就是此時rear 對應的實際下標,當 rear 為 7 時,rear 向下移動一格時,新的 rear 就是 ( 7 + 1 ) % 8 = 0, 正好就是 7 下一個的下標值 0


問題拓展 (數組下標循環的小技巧)

下標往后移動(o?set 小于 array.length): index = (index + o?set) % array.length

在這里插入圖片描述


下標往前移動(o?set 小于 array.length): index = (index + array.length - o?set) % array.length

array.length - o?set 其實就是變相地讓 小標變成向后 移動。
在這里插入圖片描述


順序隊列的代碼
public class MyQueue {int front;int rear;int[] elem;public MyQueue() {elem = new int[4];}//入隊public boolean offer(int data) {if(isFull()) {return false;}elem[rear] = data;rear = (rear + 1) % elem.length;return true;}//隊列是否已滿private boolean isFull() {return (rear + 1) % elem.length == front;}//隊列是否為空public boolean isEmpty() {return rear == front;}//出隊public int poll() {if(isEmpty()) {return -1;}int ret = elem[front];front = (front + 1) % elem.length;return ret;}//求元素個數public int size() {int count = 0;for (int i = front; i < rear; i++) {count++;}return count;}//獲取隊頭元素public int peek() {if(isEmpty()) {return -1;}return elem[front];}
}

Queue

在這里插入圖片描述
上面是我們常用的隊列方法

在這里插入圖片描述
隊列Queue本質上是一個接口,所以Queue 不能被實例化,那如何使用?

Deque (雙端隊列)

雙端隊列(deque)是指允許兩端都可以進行入隊和出隊操作的隊列,deque 是 “double ended queue” 的簡稱。
那就說明元素可以從隊頭出隊和入隊,也可以從隊尾出隊和入隊。

在這里插入圖片描述
在這里插入圖片描述
我們可以發現 Deque 其實是繼承了 Queue 接口,但是還是一個接口,還是不能實例化,那怎么使用?請看下面解說。

LinkedList 和棧與隊列的關系

在這里插入圖片描述

在這里插入圖片描述

LinkedList 有很多接口其中包括了 Deque ,而Deque 這個接口其實繼承了 Queue ,也就是隊列,所以我們可以實例化 一個LinkedList 對象然后通過 Queue 接收就可以使用普通隊列的方法,同理,通過實例化一個LinkedList 對象然后通過 Deque 接收就可以使用雙端隊列的方法


    public static void main(String[] args) {LinkedList<Integer> linkedList = new LinkedList<>();linkedList.push(1);linkedList.push(2);linkedList.push(3);System.out.println(linkedList.peek());System.out.println(linkedList.pop());System.out.println(linkedList.peek());}

在這里插入圖片描述

LinkedList還可以當成棧來使用,也就是說LinkedList還包含棧的方法,自身功能很強大。

小結:
LinkedList 不僅可以作為不帶頭的雙向循環鏈表使用,還可以當成棧或者隊列使用。


在實際工程中,使用Deque接口是比較多的,棧和隊列均可以使用該接口。

Deque<Integer> stack = new ArrayDeque<>();//雙端隊列的線性實現
Deque<Integer> queue = new LinkedList<>();//雙端隊列的鏈式實現

習題鏈接:
http://t.csdnimg.cn/aV91m

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

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

相關文章

windows USB 設備驅動程序開發-總線接口查詢

總線接口的查詢 USB 客戶端驅動程序可以獲取對USB總線驅動程序接口的引用&#xff0c;并使用它來訪問總線驅動程序例程&#xff0c;而不是使用 I/O 請求數據包 (IRP) 機制。 使用總線驅動程序接口為客戶端驅動程序提供了幾個優勢&#xff1a; 它可以使用接口的服務&#xff…

對接企業微信API自建應用配置企業可信IP

前言 為了實現系統調用團隊會議功能&#xff0c;組織發起企業微信會議&#xff0c;于是需要和企業微信做API對接。對接過程很難受&#xff0c;文檔不清晰、沒有SDK、沒有技術支持甚至文檔報文和實際接口報文都不匹配&#xff0c;只能說企業微信的API是從業以來見過的最難用的AP…

[Spring] Spring Web MVC基礎理論

&#x1f338;個人主頁:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;?熱門專欄: &#x1f9ca; Java基本語法(97平均質量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection與…

n3.平滑升級和回滾

平滑升級和回滾 1. 平滑升級流程2. 平滑升級和回滾案例 有時候我們需要對Nginx版本進行升級以滿足對其功能的需求&#xff0c;例如添加新模塊&#xff0c;需要新功能&#xff0c;而此時 Nginx又在跑著業務無法停掉&#xff0c;這時我們就可能選擇平滑升級 1. 平滑升級流程 平…

使用ChatGPT來撰寫和潤色學術論文的教程(含最新升級開桶ChatGpt4教程)

現在有了ChatGPT4o更加方便了, 但次數太少了 想要增加次數可以考慮升級開桶ChatGpt4 一、引言 在學術研究中&#xff0c;撰寫高質量的論文是一項重要的技能。本教程將介紹如何利用ChatGPT來輔助完成從論文構思到潤色的全過程。 二、使用ChatGPT寫論文 1. 寫標題 Title/Topic…

【TB作品】51單片機,MSP430單片機,STM32單片機,簡易波形發生器

https://docs.qq.com/sheet/DUEdqZ2lmbmR6UVdU?tabBB08J2二、 簡易波形發生器 &#xff08;限MSP430、STM32單片機&#xff09; 任務要求&#xff1a; 制作一個簡易波形發生器&#xff0c;具有如下功能&#xff1a; 1、能夠產生方波、正弦波&#xff0c;并可通過示波器觀察到&…

QT 多線程 QThread

繼承QThread的線程 繼承 QThread 是創建線程的一個普通方法。其中創建的線程只有 run() 方法在線程里的。其他類內定義的方法都在主線程內。 通過上面的圖我們可以看到&#xff0c;主線程內有很多方法在主線程內&#xff0c;但是子線程&#xff0c;只有 run() 方法是在子線…

基于STM32設計的藥品柜溫濕度監測系統(華為云IOT)(184)

基于STM32設計的藥品柜溫濕度監測系統(華為云IOT)(184) 文章目錄 一、前言1.1 項目介紹【1】項目功能介紹【2】整體需求總結【3】項目硬件模塊組成1.2 設計思路【1】整體設計思路【2】ESP8266工作模式配置【3】華為云IOT手機APP界面開發思路1.3 項目開發背景【1】選題的意義【2…

R語言學習筆記6-數據框

R語言學習筆記6-數據框 數據框(DataFrame)介紹數據框用途創建數據框從矩陣創建數據框索引和切片添加和修改列數據框的預處理數據框的排序數據框的合并與拆分數據框的計算與匯總數據框的篩選處理缺失值應用函數處理數據重塑數據框使用 dplyr 進行數據框的管道操作數據框的時間序…

使用 WebSocket 進行實時數據傳輸

以下是使用 WebSocket 進行實時數據傳輸的一般步驟&#xff1a; 一、前端部分 &#xff08;一&#xff09;創建 WebSocket 連接 const socket new WebSocket(ws://your-server-url); 在上述代碼中&#xff0c;將 ws://your-server-url 替換為您實際的服務器 WebSocket 地…

SvANet:微小醫學目標分割網絡,增強早期疾病檢測

SvANet&#xff1a;微小醫學目標分割網絡&#xff0c;增強早期疾病檢測 提出背景前人工作醫學對象分割微小醫學對象分割注意力機制 SvANet 結構圖SvANet 解法拆解解法邏輯鏈 論文&#xff1a;SvANet: A Scale-variant Attention-based Network for Small Medical Object Segmen…

【JAVA poi-tl-ext 富文本轉word】

富文本轉word 環境使用poi-tl-ext的原因富文本轉word代碼 環境 jdk 1.8 <dependency><groupId>io.github.draco1023</groupId><artifactId>poi-tl-ext</artifactId><version>0.4.16</version> </dependency>poi-tl-ext已經包…

可靈重大升級!新增Web端上線、首尾幀控制、單次生成視頻時長增加至10s!

快手視頻生成大模型“可靈”&#xff08;Kling&#xff09;&#xff0c;作為全球首個真正用戶可用的視頻生成大模型&#xff0c;自面世以來&#xff0c;憑借其無與倫比的視頻生成效果&#xff0c;在全球范圍內贏得了用戶的熱烈追捧與高度評價。截至目前&#xff0c;申請體驗其內…

修正版頭像上傳組件

修正版頭像上傳組件 文章說明核心源碼展示運行效果展示源碼下載 文章說明 在頭像剪切上傳一文中&#xff0c;我采用div做裁剪效果&#xff0c;感覺會有一些小問題&#xff0c;在昨天基于canvas繪制的功能中改進了一版&#xff0c;讓代碼變得更簡潔&#xff0c;而且通用性相對高…

永恒之藍:一場網絡風暴的啟示

引言 在網絡安全的漫長歷史中&#xff0c;“永恒之藍”&#xff08;EternalBlue&#xff09;是一個不可忽視的里程碑事件。它不僅揭示了網絡世界的脆弱性&#xff0c;還促使全球范圍內對網絡安全的重視達到了前所未有的高度。本文將深入探討“永恒之藍”漏洞的起源、影響及其對…

【WebGIS】從設計層面設計系統

本項目在通過現代信息技術手段&#xff0c;對古村古鎮進行多方位、多角度的數字化記錄、展示與傳播&#xff0c;實現文化遺產的數字化保護、活化利用與共享。項目內容主要包括&#xff1a;1&#xff09;古村古鎮數據庫的建立&#xff1a;通過多種渠道收集古村古鎮的各類信息&am…

期貨量化交易客戶端開源教學第八節——TCP通信服務類

private FReciveStr: AnsiString; {接收到的數據} IsConErr: Boolean; {網絡連接是否失敗} FSocket_LB: Integer; {TCP連接類別,0為交易,1為行情,2為查詢} FRetryCount: Integer; {網絡連接重試次數} FLoginErrEvent: TLoginErrEvent; {…

如何從 PDF 中刪除背景

您是否曾經收到過充滿分散注意力背景的掃描 PDF 文檔&#xff1f;也許是帶有繁忙水印的舊收據或背景光線不均勻的掃描文檔。雖然這些背景可能看起來沒什么大不了的&#xff0c;但它們會使您的工作空間變得混亂&#xff0c;并使您難以專注于重要信息。輕松刪除這些不需要的元素并…

短視頻SEO矩陣系統:源碼開發與部署全攻略

在數字化時代&#xff0c;短視頻已成為人們獲取信息、娛樂休閑的重要方式。隨著短視頻平臺的興起&#xff0c;如何讓自己的內容在眾多視頻中脫穎而出&#xff0c;成為每個創作者和內容運營者關注的焦點。本文將為您深入解析短視頻SEO矩陣系統的源碼開發與部署&#xff0c;助您在…

MT6825磁編碼IC在智能雙旋機器人中的應用

MT6825磁編碼IC在智能雙旋機器人中的應用&#xff0c;無疑為這一領域的創新和發展注入了新的活力。作為一款高性能的磁性位置傳感器&#xff0c;MT6825以其獨特的優勢&#xff0c;在智能雙旋機器人的運動控制、定位精度以及系統穩定性等方面發揮了關鍵作用。 www.abitions.com …