【數據結構】第五彈——Stack 和 Queue

文章目錄

  • 一. 棧(Stack)
    • 1.1 概念
    • 1.2 棧的使用
    • 1.3 棧的模擬實現
      • 1.3.1 順序表結構
      • 1.3.2 進棧 壓棧
      • 1.3.3 刪除棧頂元素
      • 1.3.4 獲取棧頂元素
      • 1.3.5 自定義異常
    • 1.4 棧的應用場景
      • 1.改變元素序列
      • 2. 將遞歸轉化為循環
      • 3. 四道習題
    • 1.5 概念分區
  • 二. 隊列(Queue)
    • 2.1 概念
    • 2.2 隊列的使用
    • 2.3 隊列模擬實現
    • 2.4 循環隊列
      • 數組下標循環的小技巧
      • 設計循環隊列
  • 三. 雙端隊列 (Deque)
  • 四. 兩道面試題
    • 4.1 用隊列實現棧
    • 4.2 用棧實現隊列

一. 棧(Stack)

1.1 概念

棧:一種特殊的線性表,其只允許在固定的一端進行插入和刪除元素操作。進行數據插入和刪除操作的一端稱為棧頂,另一端稱為棧底。棧中的數據元素遵守后進先出LIFO(Last In First Out)的原則。
在這里插入圖片描述

壓棧:棧的插入操作叫做進棧/壓棧/入棧,入數據在棧頂。
出棧:棧的刪除操作叫做出棧。出數據在棧頂。

1.2 棧的使用

在這里插入圖片描述

public static void main(String[] args) {Stack<Integer> s = new Stack();s.push(1);s.push(2);s.push(3);s.push(4);System.out.println(s.size());   // 獲取棧中有效元素個數---> 4System.out.println(s.peek());   // 獲取棧頂元素---> 4s.pop();   // 4出棧,棧中剩余1   2   3,棧頂元素為3System.out.println(s.pop());   // 3出棧,棧中剩余1  2   棧頂元素為3if(s.empty()){System.out.println("棧空");}else{System.out.println(s.size());}}

1.3 棧的模擬實現

在這里插入圖片描述
Stack繼承了Vector,Vector和ArrayList類似,都是動態的順序表

1.3.1 順序表結構

public class MyStack {public int[] elem;public int usedSize;public MyStack() {this.elem = new int[10];}
}

1.3.2 進棧 壓棧

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

1.3.3 刪除棧頂元素

public int pop() {if(isEmpty()) {throw new EmptyStackException();}int val = elem[usedSize-1];usedSize--;return val;}

1.3.4 獲取棧頂元素

 public int peek() {if(isEmpty()) {throw new EmptyStackException();}return elem[usedSize-1];}public boolean isEmpty() {return usedSize == 0;}

1.3.5 自定義異常

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

完整代碼:

public class MyStack {public int[] elem;public int usedSize;public MyStack() {this.elem = new int[10];}public void push(int val) {if(isFull()) {this.elem = Arrays.copyOf(elem,2*elem.length);}elem[usedSize++] = val;}public boolean isFull() {return usedSize == elem.length;}public int pop() {if(isEmpty()) {throw new EmptyStackException();}int val = elem[usedSize-1];usedSize--;return val;}//獲取棧頂元素 但是不刪除public int peek() {if(isEmpty()) {throw new EmptyStackException();}return elem[usedSize-1];}public boolean isEmpty() {return usedSize == 0;}
}

1.4 棧的應用場景

1.改變元素序列

在這里插入圖片描述

2. 將遞歸轉化為循環

逆序打印鏈表

// 遞歸方式
void printList(Node head){if(null != head){printList(head.next);System.out.print(head.val + " ");}
}// 循環方式
void printList(Node head){if(null == head){return;}Stack<Node> s = new Stack<>();// 將鏈表中的結點保存在棧中Node cur = head;while(null != cur){s.push(cur);cur = cur.next;}// 將棧中的元素出棧while(!s.empty()){System.out.print(s.pop().val + " ");}
}

3. 四道習題

在這里插入圖片描述

都是力扣牛客網上的題目,也是常見的面試題,會在刷題專欄詳細講解

1.5 概念分區

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

  • 棧是一種通用的數據結構概念,而虛擬機棧是在 Java 虛擬機環境下對棧這種數據結構的具體應用
  • 虛擬機棧由多個棧幀組成,每個棧幀對應一個方法的調用。當方法調用開始時,會創建一個新的棧幀并壓入虛擬機棧;當方法調用結束時,對應的棧幀會從虛擬機棧中彈出
  • 綜上所述,棧是一種抽象的數據結構,虛擬機棧是 JVM 中使用棧結構來管理方法調用的具體實現,而棧幀則是虛擬機棧中用于支持單個方法執行的具體數據結構

二. 隊列(Queue)

2.1 概念

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

2.2 隊列的使用

在Java中,Queue是個接口,底層是通過鏈表實現的
在這里插入圖片描述

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

每個方法都有一個類似的方法
從效果上沒有區別
在這里插入圖片描述

注意:Queue是個接口,在實例化時必須實例化LinkedList的對象,因為LinkedList實現了Queue接口

在這里插入圖片描述

在這里插入圖片描述

LinkedList實現的方法是很多的,可以直接拿來用
那就要這樣寫了:

LinkedList <Integer> q = new LinkedList<>();

2.3 隊列模擬實現

隊列中既然可以存儲元素,那底層肯定要有能夠保存元素的空間,通過前面線性表的學習了解到常見的空間類型有兩種:順序結構 和 鏈式結構

隊列的實現使用順序結構還是鏈式結構好?

我們先說鏈式結構:
在這里插入圖片描述
在這里插入圖片描述
雙向鏈表實現隊列

 static class ListNode{public int val;public ListNode prev;public ListNode next;public ListNode(int val){this.val=val;}}public ListNode first=null;public ListNode last=null;public int useSize=0;public void offer(int val){//addLast尾插ListNode node=new ListNode(val);if(isEmpty()){first=last=null;}last.next=node;node.prev=last;last=last.next;useSize++;}public int poll(){//頭刪if(isEmpty()){return -1;}int val= first.val;//隊頭的數據first=first.next;if(first!=null){//只剩一個節點 直接useSize--first.prev=null;}useSize--;return 0;}public int peek(){//獲取隊頭元素if(first==null){return -1;}return first.val;}public boolean isEmpty(){return useSize==0;}

雙向鏈表實現隊列效率很高 刪除 插入都很方便

如果是數組實現隊列該如何實現?

其實按照順序遍歷插入刪除 可以實現,但是數組的遍歷 一旦往后走就無法回去 被刪除的空間沒辦法再次使用了

如果數組是一個環就好了,這樣就可以走回去再次使用空間–這就是循環隊列

2.4 循環隊列

我們有時還會使用一種隊列叫循環隊列如操作系統課程講解生產者消費者模型時可能就會使用循環隊列。環形隊列通常使用數組實現。

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

上面兩個一個是空的環形隊列 一個是滿的環形隊列

實現環形隊列兩個問題:
1.怎么判斷空和滿?
2.rear 和 front 下標從7到0怎么做到的?

解答:
空:只要front 和 rear 相遇就是空的
滿 有三種方法判斷
1.定義size size=數組長度就是滿
2.添加標記 boolean類型元素 一開始是false一旦開始添加元素就變為true
3.浪費一個空間 判斷rear是不是front

先放入元素 再rear++ 判斷rear的下一個元素是不是front就可以了
在這里插入圖片描述

判斷 rear=(rear+1)%len

關于這個公式:

數組下標循環的小技巧

在這里插入圖片描述
在這里插入圖片描述
利用取模運算得到下標

好了,解決了這兩個問題,我們可以使用循環隊列了,正好我們來看一道設計循環隊列的題目

設計循環隊列

設計循環隊列

class MyCircularQueue {//數組實現public int front;public int rear;public int[] elem;public MyCircularQueue(int k) {//使用浪費一個空間的方法來判斷隊列是否滿//數組多給一個空間elem=new int[k+1];}public boolean enQueue(int value) {//插入 判滿if(isFull()){return false;}elem[rear]=value;rear =(rear+1)%elem.length;return true;}public boolean deQueue() {//刪除 判空if(isEmpty()){return false;}//頭向后走 因為是環形的所以 向后走也不用擔心前面的空間不能使用了front=(front+1)%elem.length;return true;}public int Front() {if(isEmpty()){return -1;}return elem[front];}public int Rear() {if(isEmpty()){return-1;}//return elem[rear];}public boolean isEmpty() {return rear==front;}public boolean isFull() {//rear 的下一個是 frontreturn (rear+1)%elem.length==front;}
}/*** Your MyCircularQueue object will be instantiated and called as such:* MyCircularQueue obj = new MyCircularQueue(k);* boolean param_1 = obj.enQueue(value);* boolean param_2 = obj.deQueue();* int param_3 = obj.Front();* int param_4 = obj.Rear();* boolean param_5 = obj.isEmpty();* boolean param_6 = obj.isFull();*/

如果是這樣寫示例測到這里會有一個報錯
原因在于我們并沒有考慮 最重要的一點
rear 從尾到頭 怎么辦 front刪除是向后走了 rear等于0 是可以的
rear 的下一個確實不是front 可以等于0
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

正確代碼如下:

class MyCircularQueue {//數組實現public int front;public int rear;public int[] elem;public MyCircularQueue(int k) {//使用浪費一個空間的方法來判斷隊列是否滿//數組多給一個空間elem=new int[k+1];}public boolean enQueue(int value) {//插入 判滿if(isFull()){return false;}elem[rear]=value;rear =(rear+1)%elem.length;return true;}public boolean deQueue() {//刪除 判空if(isEmpty()){return false;}//頭向后走 因為是環形的所以 向后走也不用擔心前面的空間不能使用了front=(front+1)%elem.length;return true;}public int Front() {if(isEmpty()){return -1;}return elem[front];}public int Rear() {if(isEmpty()){return-1;}//int index=(rear==0)?elem.length-1:rear-1;return elem[index];}public boolean isEmpty() {return rear==front;}public boolean isFull() {//rear 的下一個是 frontreturn (rear+1)%elem.length==front;}
}

三. 雙端隊列 (Deque)

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

在這里插入圖片描述

Deque是一個接口,使用時必須創建LinkedList的對象
在實際工程中,使用Deque接口是比較多的,棧和隊列均可以使用該接口

再來看一下我們數據結構第一篇文章畫的圖,想打關一樣,已經學完這么多了

在這里插入圖片描述
兩種使用方式

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

四. 兩道面試題

4.1 用隊列實現棧

隊列實現棧
在這里插入圖片描述

class MyStack {public Queue<Integer> qu1;public Queue<Integer> qu2;public MyStack() {qu1=new LinkedList<>();qu2=new LinkedList<>();}//入棧public void push(int x) {if(!qu1.isEmpty()){qu1.offer(x);}else if(!qu2.isEmpty()){qu2.offer(x);}else{qu1.offer(x);}}//出棧public int pop() {if(empty()){return-1;}else if(!qu1.isEmpty()){ // 1不是空 將1的size-1個元素放到2for(int i=0;i<qu1.size()-1;i++){qu2.offer(qu1.poll());}return qu1.poll();}else{//2 不為空for(int i=0;i<qu2.size()-1;i++){qu1.offer(qu2.poll());}return qu2.poll();}}public int top() {if(empty()){return-1;}//用一個臨時變量 把每個刪除的都記錄一下,最后一個就是棧頂if(!qu1.isEmpty()){ // 1不是空 將1的size-1個元素放到2int val=0;for(int i=0;i<qu1.size();i++){val=qu1.poll();qu2.offer(val);}return val;}else{//2 不為空int val=0;for(int i=0;i<qu2.size();i++){val=qu2.poll();qu1.offer(val);}return val;}}public boolean empty() {return qu1.isEmpty()&&qu2.isEmpty();}
}

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

class MyStack {public Queue<Integer> qu1;public Queue<Integer> qu2;public MyStack() {qu1=new LinkedList<>();qu2=new LinkedList<>();}//入棧public void push(int x) {if(!qu1.isEmpty()){qu1.offer(x);}else if(!qu2.isEmpty()){qu2.offer(x);}else{qu1.offer(x);}}//出棧public int pop() {if(empty()){return-1;}else if(!qu1.isEmpty()){ // 1不是空 將1的size-1個元素放到2int size=qu1.size();for(int i=0;i<size-1;i++){qu2.offer(qu1.poll());}return qu1.poll();}else{//2 不為空int size=qu2.size();for(int i=0;i<size-1;i++){qu1.offer(qu2.poll());}return qu2.poll();}}public int top() {if(empty()){return-1;}//用一個臨時變量 把每個刪除的都記錄一下,最后一個就是棧頂if(!qu1.isEmpty()){ // 1不是空 將1的size-1個元素放到2int size=qu1.size();int val=0;for(int i=0;i<size;i++){val=qu1.poll();qu2.offer(val);}return val;}else{//2 不為空int size=qu2.size();int val=0;for(int i=0;i<size;i++){val=qu2.poll();qu1.offer(val);}return val;}}public boolean empty() {return qu1.isEmpty()&&qu2.isEmpty();}
}

4.2 用棧實現隊列

在這里插入圖片描述
按照我們畫圖得到的思路,寫代碼:

class MyQueue {
// 兩個棧
public ArrayDeque<Integer> s1;
public ArrayDeque<Integer> s2;public MyQueue() {s1=new ArrayDeque<>();s2=new ArrayDeque<>();}public void push(int x) {//入隊s1.push(x);}public int pop() {if(empty()){return -1;}if(s2.isEmpty()){while(!s1.isEmpty()){s2.push(s1.pop());}}return s2.pop();}public int peek() {if(empty()){return -1;}if(s2.isEmpty()){while(!s1.isEmpty()){s2.push(s1.pop());}}return s2.peek();}public boolean empty() {return s1.isEmpty()&&s2.isEmpty();}
}

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

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

相關文章

第七屆能源系統與電氣電力國際學術會議(ICESEP 2025)

重要信息 時間&#xff1a;2025年6月20-22日 地點&#xff1a;中國-武漢 官網&#xff1a;www.icesep.net 主題 能源系統 節能技術、能源存儲技術、可再生能源、熱能與動力工程 、能源工程、可再生能源技術和系統、風力發…

深入解析C++ STL Stack:后進先出的數據結構

一、引言 在計算機科學中&#xff0c;棧&#xff08;Stack&#xff09;作為一種遵循后進先出&#xff08;LIFO&#xff09;?原則的數據結構&#xff0c;是算法設計和程序開發的基礎構件。C STL中的stack容器適配器以簡潔的接口封裝了底層容器的操作&#xff0c;為開發者提供了…

Golang | 自行實現并發安全的Map

核心思路&#xff0c;讀寫map之前加鎖&#xff01;哈希思路&#xff0c;大map化分為很多個小map

Mac 「brew」快速安裝MySQL

安裝MySQL 在 macOS 上安裝 MySQL 環境可以通過Homebrew快速實現&#xff0c;以下是步驟指南&#xff1a; 方法 1&#xff1a;使用 Homebrew 安裝 MySQL 1. 安裝 Homebrew 如果尚未安裝 Homebrew&#xff0c;可以通過以下命令安裝&#xff1a; /bin/bash -c "$(curl -…

【數字孿生世界的搭建之旅:從0到1理解飛渡平臺】

數字孿生世界的搭建之旅&#xff1a;從0到1理解飛渡平臺 前言&#xff1a;數字分身的魔法 想象一下&#xff0c;如果你能在現實世界之外&#xff0c;創造一個物理世界的"分身"&#xff0c;這個分身能完美復制現實中的一切變化&#xff0c;甚至可以預測未來可能發生…

【漏洞復現】Struts2系列

【漏洞復現】Struts2系列 1. 了解Struts21. Struts2 S2-061 RCE &#xff08;CVE-2020-17530&#xff09;1. 漏洞描述2. 影響版本3. 復現過程 1. 了解Struts2 Apache Struts2是一個基于MVC設計模式的Web應用框架&#xff0c;會對某些標簽屬性&#xff08;比如 id&#xff09;的…

[FPGA Video IP] Video Processing Subsystem

Xilinx Video Processing Subsystem IP (PG231) 詳細介紹 概述 Xilinx LogiCORE? IP Video Processing Subsystem (VPSS)&#xff08;PG231&#xff09;是一個高度可配置的視頻處理模塊&#xff0c;設計用于在單一 IP 核中集成多種視頻處理功能&#xff0c;包括縮放&#xf…

自動駕駛(ADAS)功能--相關名稱及縮寫

根據《道路車輛先進駕駛輔助系統&#xff08;ADAS&#xff09;術語及定義》GB/T 39263—2020&#xff0c;如下表格&#xff1a; 編號中文術語英文縮寫定義類別2.1.1先進駕駛輔助系統ADAS利用傳感、通信、決策及執行等裝置&#xff0c;實時監測駕駛員、車輛及行駛環境&#xff…

1.9軟考系統架構設計師:優秀架構設計師 - 超簡記憶要點、知識體系全解、考點深度解析、真題訓練附答案及解析

超簡記憶要點 1. 優秀架構師標準 ? 技術&#xff08;深度/廣度&#xff09; 實戰&#xff08;大型項目&#xff09; 素養&#xff08;溝通/業務前瞻&#xff09; 2. 演化路徑 &#x1f4c8; 積累&#xff08;技術/項目&#xff09; → 思維&#xff08;系統視角/抽象建模&…

(MySQL)庫的操作

目錄 創建數據庫 語法 創建數據庫實例 不使用可選項 使用可選項1 字符集和校驗規則 校驗規則對數據庫的影響 不區分大小寫 查看配置 添加可選項2 操縱數據庫 使用數據庫 查看數據庫 查看所有數據庫 查詢當前正在使用的數據庫名稱 顯示創建數據庫語句 修改數據庫…

10.ArkUI Grid的介紹和使用

ArkUI Grid 組件詳解與使用指南 Grid 是 ArkUI 中用于實現網格布局的容器組件&#xff0c;能夠以行和列的形式排列子組件。以下是 Grid 組件的詳細介紹和使用方法。 基本介紹 Grid 組件特點&#xff1a; 支持固定列數和自適應布局提供靈活的間距和排列控制支持滾動顯示大量…

目標檢測原理簡介

目標檢測是一類計算機視覺任務,簡單來說,目標檢測可被定義為在計算機中輸入一張圖像,計算機需要找出圖像中所有感興趣的目標(物體),確定它們的類別和位置,如圖一所示。目標檢測是計算機視覺領域的核心問題之一,相較于最原始的將整張圖片分類為某一類別,目標檢測不光可…

ZYNQ筆記(十四):基于 BRAM 的 PS、PL 數據交互

版本&#xff1a;Vivado2020.2&#xff08;Vitis&#xff09; 實驗任務&#xff1a; PS 將字符串數據寫入BRAM&#xff0c;再將數據讀取出來&#xff1b;PL 從 BRAM 中讀取數據&#xff0c;bing。通過 ILA 來觀察讀出的數據&#xff0c;與前面串口打印的數據進行對照&#xff0…

Python-Django系列—部件

部件是 Django 對 HTML 輸入元素的表示。部件處理 HTML 的渲染&#xff0c;以及從對應于部件的 GET&#xff0f;POST 字典中提取數據。 內置部件生成的 HTML 使用 HTML5 語法&#xff0c;目標是 <!DOCTYPE html>。例如&#xff0c;它使用布爾屬性&#xff0c;如 checked…

【Leetcode 每日一題】2799. 統計完全子數組的數目

問題背景 給你一個由 正 整數組成的數組 n u m s nums nums。 如果數組中的某個子數組滿足下述條件&#xff0c;則稱之為 完全子數組 &#xff1a; 子數組中 不同 元素的數目等于整個數組不同元素的數目。 返回數組中 完全子數組 的數目。 子數組 是數組中的一個連續非空序…

卷積神經網絡(二)

1 卷積運算的兩個問題&#xff1a; 1.1 圖像邊緣信息使用少 邊緣的像素點可能只會被用一次或者2次&#xff0c;中間的會用的更多。 1.2 圖像被壓縮 5*5的圖像&#xff0c;如果經過3*3的卷積核后&#xff0c;大小變成3*3的。 N*N的圖像&#xff0c;果經過F*F的卷積核后&#x…

組網技術-DHCP服務器,RIP協議,OSPF協議

1.DHCP Server提供三種IP地址分配策略&#xff1a; 手工分配地址 自動分配地址 n 動態分配地址 2.DHCP報文類型 DHCP DISCOVER(廣播)&#xff1a;用于尋址DHCP Server DHCP OFFER&#xff08;單播&#xff09;&#xff1a;攜帶分配給客戶端的IP地址 DHCP REQUEST&#xff08;…

反爬策略應對指南:淘寶 API 商品數據采集的 IP 代理與請求偽裝技術

一、引言? 在電商數據驅動決策的時代&#xff0c;淘寶平臺海量的商品數據極具價值。然而&#xff0c;淘寶為保障平臺安全和用戶體驗&#xff0c;構建了嚴密的反爬體系。當采集淘寶 API 商品數據時&#xff0c;若不采取有效措施&#xff0c;頻繁的請求極易觸發反爬機制&#x…

學習筆記(算法學習+Maven)

單調隊列優化多重背包 #include <bits/stdc.h> using namespace std; const int M 2010; const int N 20010; int q[N]; int hh 0, tt -1; int f[N]; int g[N]; int v[M], w[M], s[M]; int n, m; int main() { cin >> n >> m; for (int i 1; …

WPF之項目創建

文章目錄 引言先決條件創建 WPF 項目步驟理解項目結構XAML 與 C# 代碼隱藏第一個 "Hello, WPF!" 示例構建和運行應用程序總結相關學習資源 引言 Windows Presentation Foundation (WPF) 是 Microsoft 用于構建具有豐富用戶界面的 Windows 桌面應用程序的現代框架。它…