數據結構線性表-棧和隊列的實現

1. 棧(Stack)

1.1 概念

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

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

出棧:棧的刪除操作叫做出棧。出數據在棧頂。

1.2 棧的使用

從上圖中可以看到,Stack繼承了Vector,Vector和ArrayList類似,都是動態的順序表,不同的Vector是線程安全;Vector類,是線程安全的動態數組,但是性能較差 , 現在已經不是很常用了 , 可以說已經過時了。

常用方法

方法功能
Stack()構造一個空的棧
E push(E e)將e入棧,并返回e
E pop()將棧頂元素出棧并返回
E peek()獲取棧頂元素
int size()獲取棧中有效元素個數
boolean empty()檢測棧是否為空

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()); // 獲取棧中有效元素個數---> 4
System.out.println(s.peek()); // 獲取棧頂元素---> 4
s.pop(); // 4出棧,棧中剩余1 2 3,棧頂元素為3
System.out.println(s.pop()); // 3出棧,棧中剩余1 2 棧頂元素為3
if(s.empty()){
System.out.println("棧空");
}else{
System.out.println(s.size());}
}

1.3 棧的模擬實現

從上圖中可以看到,Stack繼承了Vector,Vector和ArrayList類似,都是動態的順序表,不同的是Vector是線程安 全的。

代碼實現

1. 構造方法

class MyStack{private int[] arr;// size 記錄棧中元素個數private int size;public MyStack(){// 調用無參構造方法 默認最大容量12this(12);}public MyStack(int MaxSize){this.arr = new int[MaxSize];}
}

2. 入棧(push)

// 入棧public int push(int value){if(this.size == arr.length){// 棧滿 ,需要擴容int[] copyArr;// 復制arr 數組并擴容一倍copyArr = Arrays.copyOf(arr,2 * arr.length);arr = copyArr;}//將元素添加到size位置this.arr[size] = value;// 元素個數加一this.size++;// 返回添加元素return value;}

3. 出棧(pop)

// 出棧public int pop(){if(this.size == 0){//沒有元素//拋出運行時異常,此處也可以自定義異常throw new RuntimeException("棧中沒有元素,不能出棧....");}// 獲得棧頂元素int value = this.arr[size - 1];// size - 1 之后, 下一次插入時會覆蓋原數據,利用覆蓋替代刪除this.size--;return value;}

4.獲取棧頂元素(peek)

// 獲取棧頂元素public int peek(){if(this.size == 0){//沒有元素//拋出運行時異常,此處也可以自定義異常throw new RuntimeException("棧中沒有元素,不能出棧....");}return this.arr[this.size - 1];}

5.獲取元素個數(getSize)

//獲取元素個數public int getSize(){return this.size;}

6.判斷棧是否為空(isEmpty)

//判斷元素是否為空public boolean isEmpty(){return this.size == 0;}

完整代碼

import java.util.Arrays;public class MyStack{private int[] arr;// size 記錄棧中元素個數private int size;public MyStack(){// 調用無參構造方法 默認最大容量12this(12);}public MyStack(int MaxSize){this.arr = new int[MaxSize];}// 入棧public int push(int value){if(this.size == arr.length){// 棧滿 ,需要擴容int[] copyArr;// 復制arr 數組并擴容一倍copyArr = Arrays.copyOf(arr,2 * arr.length);arr = copyArr;}//將元素添加到size位置this.arr[size] = value;// 元素個數加一this.size++;// 返回添加元素return value;}// 出棧public int pop(){if(isEmpty()){//沒有元素//拋出運行時異常,此處也可以自定義異常throw new RuntimeException("棧中沒有元素,不能出棧....");}// 獲得棧頂元素int value = this.arr[size - 1];// size - 1 之后, 下一次插入時會覆蓋原數據,利用覆蓋替代刪除this.size--;return value;}// 獲取棧頂元素public int peek(){if(isEmpty()){//沒有元素//拋出運行時異常,此處也可以自定義異常throw new RuntimeException("棧中沒有元素,不能出棧....");}return this.arr[this.size - 1];}//獲取元素個數public int getSize(){return this.size;}//判斷元素是否為空public boolean isEmpty(){return this.size == 0;}
}

1.4 棧的應用場景

1. 改變元素的序列

1. 若進棧序列為 1,2,3,4 ,進棧過程中可以出棧,則下列不可能的一個出棧序列是( )

? ? ?A: 1,4,3,2? ? ? ? ? ? ? ? ? ? ? B: 2,3,4,1? ? ? ? ? ? ? ? ?C: 3,1,4,2? ?? ? ? ? ? ? ? ? ? ? ? ? ?D: 3,4,2,1

根據棧先進后出的性質,結合題目中進棧的過程中也可以出棧,如A選項:1進1出,2進3進4進,4出3出2出即符合題意,同理C選項,1進2進3進3出之后不可能直接出1,故C選項不可能實現。

2.一個棧的初始狀態為空。現將元素1、2、3、4、5、A、B、C、D、E依次入棧,然后再依次出棧,則元素出棧的順 序是( )。

A: 12345ABCDE? ? ? ? ? B: EDCBA54321? ? ? ? ?C: ABCDE12345? ? ? ? ? ?D: 54321EDCBA

先進后出,依次入棧,依次出棧,故B選項合理

2. 將遞歸轉化為循環

遞歸實現逆序打印

 public void display(ListNode head){if(head == null){return;}//直到鏈表末尾,再歸回去if(head.next == null){System.out.println(head.val+" ");return;}display(head.next);System.out.println(head.val+" ");
}

使用棧實現逆序打印

public void display(ListNode head){if(head == null){return;}Stack<ListNode> stack  = new Stack<>();ListNode cur = head;while(cur!= null){stack.push(cur);cur = cur.next;}while(!stack.empty()){ListNode ret =   stack.pop();System.out.println(ret.val+" ");}}

2. 隊列(Queue)

2.1 概念

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

入隊列:進行插入操作的一端稱為隊尾(Tail/Rear)

出隊列:進行刪除操作的一端稱為隊頭 (Head/Front)

2.2 隊列的使用

在Java中,Queue是個接口,底層是通過鏈表實現的。


方法功能
boolean offer(E e)?入隊列
E poll()?出隊列
peek()?獲取隊頭元素
int size()?獲取隊列中有效元素個數
boolean isEmpty()檢測隊列是否為空

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

public static void main(String[] args) {
Queue<Integer> q = new LinkedList<>();
q.offer(1);
q.offer(2);
q.offer(3);
q.offer(4);
q.offer(5); // 從隊尾入隊列
System.out.println(q.size());
System.out.println(q.peek()); // 獲取隊頭元素
q.poll();
System.out.println(q.poll()); // 從隊頭出隊列,并將刪除的元素返回
if(q.isEmpty()){
System.out.println("隊列空");
}else{
System.out.println(q.size());
}
}

2.3 隊列模擬實現

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

 
public class Queue {// 雙向鏈表節點public static class ListNode{ListNode next;ListNode prev;int value;ListNode(int value){this.value = value;}}ListNode first; // 隊頭ListNode last; // 隊尾int size = 0;// 入隊列---向雙向鏈表位置插入新節點public void offer(int e){ListNode newNode = new ListNode(e);if(first == null){first = newNode;
// last = newNode;}else{last.next = newNode;newNode.prev = last;
// last = newNode;}last = newNode;size++;}// 出隊列---將雙向鏈表第一個節點刪除掉public int poll(){
// 1. 隊列為空
// 2. 隊列中只有一個元素----鏈表中只有一個節點---直接刪除
// 3. 隊列中有多個元素---鏈表中有多個節點----將第一個節點刪除int value = 0;if(first == null){return null;}else if(first == last){last = null;first = null;}else{value = first.value;first = first.next;first.prev.next = null;first.prev = null;}--size;return value;}// 獲取隊頭元素---獲取鏈public int peek(){if(first == null){return null;}return first.value;}public int size() {return size;}public boolean isEmpty(){return first == null;}
}

2.4 循環隊列

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

數組下標循環的小技巧?

1. 下標最后再往后(offset?小于 array.length): index = (index + offset) % array.length

2. 下標最前再往前(offset 小于 array.length): index = (index + array.length - offset)%array.length

如何區分空與滿

1. 通過添加 size 屬性記錄
2. 保留一個位置
3. 使用標記

public class CircularQueue {private int front;private int rear;private int[] circle;public CircularQueue(int k) {//浪費掉一個存儲空間circle = new int[k+1];}//入隊列public boolean enQueue(int value) {if (isFull()) {return false;}circle[rear] = value;//因為是循環隊列,不能寫++,要以取模的方式rear = (rear + 1) % circle.length;return true;}//出隊列public boolean deQueue() {if (isEmpty()) {return false;}front = (front + 1) % circle.length;return true;}//返回隊頭元素public int Front() {if (isEmpty()) {return -1;}return circle[front];}//返回隊尾元素public int Rear() {if (isEmpty()) {return -1;}return circle[(rear - 1 + circle.length) % circle.length];}public boolean isEmpty() {return rear == front;}public boolean isFull() {return ((rear + 1) % circle.length) == front;}}

3.? 雙端隊列 (Deque)

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

Deque是一個接口,使用時必須創建LinkedList的對象。

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

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

4. 棧和隊列的互相實現

用棧實現隊列:

class MyQueue {public Stack<Integer> stack1;public Stack<Integer> stack2;public MyQueue() {stack1 = new Stack<>();stack2 = new Stack<>();}public void push(int x) {stack1.push(x);}public int pop() {if (stack2.isEmpty()) {
in2out();}return stack2.pop();}public int peek() {if (stack2.isEmpty()){
in2out();}return stack2.peek();}public boolean empty() {return stack1.isEmpty() && stack2.isEmpty();}private void in2out() {while (!stack1.isEmpty()) {stack2.push(stack1.pop());}}
}

用隊列實現棧:

class MyStack {Queue<Integer> queue1;Queue<Integer> queue2;public MyStack() {queue1 = new LinkedList<Integer>();queue2 = new LinkedList<Integer>();}public void push(int x) {queue2.offer(x);while (!queue1.isEmpty()) {queue2.offer(queue1.poll());}Queue<Integer> temp = queue1;queue1 = queue2;queue2 = temp;}public int pop() {return queue1.poll();}public int top() {return queue1.peek();}public boolean empty() {return queue1.isEmpty();}
}

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

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

相關文章

Vue學習計劃-Vue2--Vue核心(三)methods和computed

Vue 1. 事件 v-on 基礎 使用 v-on:xxx或者xxx綁定事件&#xff0c;其中xxx是事件名 事件的回調需要配置在methods對象中&#xff0c;最終會在vm上 methods中配置函數&#xff0c;不要用箭頭函數&#xff0c;否則this就不是vm了 methods中配置函數&#xff0c;都是被Vue管…

Seata使用

本文以seata-server-1.5.2&#xff0c;以配置中心、注冊中心使用Nacos&#xff0c;store.modedb&#xff08;mysql&#xff09;為例進行操作。 一、Seata Server端 1、下載seata server 鏈接: http://seata.io/zh-cn/blog/download.html下載壓縮包&#xff0c;解壓至非中文目錄…

Java技術棧 —— 微服務框架Spring Cloud —— Ruoyi-Cloud 學習(一)

Ruoyi-cloud 項目學習 一、項目環境搭建與啟動1.1 nacos安裝部署1.1.1 nacos安裝、啟動1.1.2 nacos部署 1.2 seata安裝部署1.3 后端部署與運行1.3.1 ruoyi-modules-file模塊運行報錯 1.4 nginx安裝、部署、配置與啟動1.5 redis安裝與部署1.6 前段框架知識1.7 項目啟動1.8 參考 …

實用方法 | 搭建真正滿足用戶需求的在線幫助中心

隨著互聯網的普及和信息技術的快速發展&#xff0c;客戶服務和支持變得越來越重要。為了提高客戶滿意度和維持良好的品牌形象&#xff0c;越來越多企業都開始搭建自己的在線幫助中心。 不知從何下手&#xff1f;細想一下&#xff0c;搭建在線幫助中心主要就是為了解決用戶的問…

根據java類名找出當前是哪個Excel中的sheet

pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 …

shell_81.Linux在命令行中創建使用函數

在命令行中使用函數 在命令行中創建函數 兩種方法 單行方式來定義函數&#xff1a; $ function divem { echo $[ $1 / $2 ]; } $ divem 100 5 20 $ 當你在命令行中定義函數時&#xff0c;必須在每個命令后面加個分號&#xff0c;這樣 shell 就能知道哪里是命令的起止了&am…

反射實現tomcat

獲取類信息的方法 1.通過類對象 x.getClass() 2.通過class.forname方法 Class.forname(className);這里className是存儲類名的字符串 3.通過類名.class 類名.class 通過類名創建對象 類名.newInstance&#xff08;&#xff09;&#xff1b; 反射可以看到類的一切信息&#xff1…

C語言聯合和枚舉講解

目錄 聯合體的大小 聯合體如何省空間 巧用聯合體 聯合判斷大小端&#xff08;驚為天人&#xff0c;大佬寫的&#xff0c;我借鑒&#xff09; 枚舉 枚舉類型的使用 首先我們先看一下菜鳥教程中的對C語言聯合體的說明 聯合體的大小 #include <stdio.h> union u {char…

Proteus仿真--基于ADC0808設計的調溫報警器

本文介紹基于ADC0808實現的調溫報警器設計&#xff08;完整仿真源文件及代碼見文末鏈接&#xff09; 溫度調節使用滑動變阻器模擬實現&#xff0c;ADC0808采集信號并輸出在LCD上面顯示&#xff0c;報警系統是LED燈和蜂鳴器實現聲光電報警 仿真圖如下 仿真運行視頻 Proteus仿真…

Java實現二分法的案例,什么是二分法

文章目錄 Java實現二分法的案例&#xff0c;什么是二分法二分法實現 Java實現二分法的案例&#xff0c;什么是二分法 二分法 概念&#xff1a; 二分法&#xff08;Bisection method&#xff09; 即一分為二的方法&#xff0c;又叫折半查找方法。把一組有序數列分為左右兩部分…

前程無憂接口分析

前程無憂接口分析 所需用到的工具URL解析通過抓包軟件或者開發者選項抓取數據包對代碼中的參數解析分析對acw_sc__v2進行分析對acw_sc__v2進行轉換代碼生成生成outPutList數組生成arg2參數生成arg3參數最終的效果 對詳情頁面的分析對timestamp__1258的生成分析 所需用到的工具 …

Vue3.0優點詳解

相對于Vue2.0 3.0有了比較大的改進&#xff0c;優勢主要有以下幾點&#xff1a; 一、性能提升 1、Vue3.0的響應式系統使用了Proxy代理對象&#xff0c;取代了Vue2.0中的Object.defineProperty&#xff0c;使得Vue3.0的響應式系統更快、更靈活。 2、Vue3.0對TypeScript的支持更…

Ubuntu22.04安裝完成后便可直接使用鍵盤上的Print鍵進行截圖

概要&#xff1a;Ubuntu22.04安裝完成后&#xff0c;無需安裝什么截圖軟件&#xff0c;可以直接使用鍵盤上的Print鍵進行截圖。 1、按一下Print鍵 我的電腦上Print鍵是PrtSc&#xff0c;如下圖所示 2、框選區域并截圖 如下圖中&#xff0c;可以框選(Selection)&#xff0c;也…

【教學類-35-06】17號的學號字帖延伸出的全體字帖(1-9去0)(A4豎版1份)

作品展示 背景需求&#xff1a; 給大4班17號同學單獨做了一個學號字帖后&#xff0c;我想可以把這樣的學具用在中班&#xff08;我馬上要成為中4班老師了&#xff09;&#xff0c;那就需要給全班做一份這樣的大號學號貼。 使用17號同學的word模板&#xff08;見下文&#xff…

3dMax vs Cinema4d哪個更好更適合你?

Cinema 4d和3dMax的區別 用于游戲風格、開發和風格可視化的3D建模、動畫和渲染軟件系統&#xff0c;為用戶提供制作和編輯動畫、視覺效果和環境的靈活性。4D CINEMA可能是由MAXON構建的強大的3D建模、運動圖形、繪畫和動畫軟件系統。Cinema 4D將在每個Windows和MAC操作系統上運…

多目標追蹤評價指標

多目標追蹤性能評價 基礎&#xff1a; GT&#xff1a;Ground Truth&#xff0c;是指真實的標簽或者真實的對象&#xff1b; TP&#xff1a;True Positive&#xff0c;被正確預測檢測到的樣本&#xff1b; TN&#xff1a;True Negative&#xff0c;被預測為負的負樣本&#…

啃下這50道筆試題,你就是SQL專家!(附答案,收藏備用)

【關注微信公眾號&#xff1a;跟強哥學SQL&#xff0c;回復“筆試”免費領取大廠SQL筆試題。】 有兩個名為Department&#xff08;部門&#xff09;和Employees&#xff08;員工&#xff09;的表結構如下&#xff1a; CREATE TABLE Department ( DepId int, DepName va…

文章解讀與仿真程序復現思路——電力系統自動化EI\CSCD\北大核心《考慮兩階段魯棒優化配置的多微網合作博弈》

這個標題涉及到多個概念&#xff0c;讓我們逐步解讀&#xff1a; 考慮兩階段魯棒優化配置&#xff1a; 兩階段&#xff1a; 指的是在解決問題或進行優化時&#xff0c;可能存在兩個不同的階段或步驟。這表明問題的解決不是一步完成的&#xff0c;而是需要經過多個步驟或階段。魯…

前端學習系列之CSS

目錄 CSS 簡介 發展史 優勢 基本語法 引用方式 內部樣式 行內樣式 外部樣式 選擇器 id選擇器 class選擇器 標簽選擇器 子代選擇器 后代選擇器 相鄰兄弟選擇器 后續兄弟選擇器 交集選擇器 并集選擇器 通配符選擇器 偽類選擇器 屬性選擇器 CSS基本屬性 優…

virtualenv創建虛擬環境

目錄 概念安裝創建虛擬環境激活虛擬環境刪除虛擬環境退出虛擬環境更改虛擬環境路徑概念 virtualenv是一個創建隔離的Python運行環境的工具。它允許用戶為每個Python項目創建一個獨立的虛擬環境,以避免不同項目之間的依賴沖突。 安裝 pip install virtualenv virtualenvwrapper…