Java棧和基礎(chǔ)隊(duì)列的實(shí)現(xiàn)詳解
棧和隊(duì)列:都是線性表,都是基于List基礎(chǔ)上的實(shí)現(xiàn)
線性表:數(shù)組,鏈表,字符串,棧,隊(duì)列
元素按照一條“直線”排列,線性表這個(gè)結(jié)構(gòu)中,一次添加單個(gè)元素
棧(stack)
一種特殊的線性表,其只允許在固定的一端進(jìn)行插入和刪除元素操作。進(jìn)行數(shù)據(jù)插入和刪除操作的一端稱為棧頂,另一端稱為棧底。棧中的數(shù)據(jù)元素遵守后進(jìn)先出LIFO(Last In First Out)的原則。
棧支持的三個(gè)核心操作:
- 入棧push
- 出棧pop
- 返回棧頂元素peek
棧的常見實(shí)際應(yīng)用:
- 無(wú)處不在的撤銷操作undo,一般任意的編輯器都使用 ctrl + z 操作,其實(shí)本質(zhì)就是每次操作一次 ctrl + z 就是一次棧的pop
- 瀏覽器的前進(jìn)后退,瀏覽器維護(hù)了一個(gè)棧結(jié)構(gòu)A->B->C,此時(shí)頁(yè)面停留在C,想要回到頁(yè)面B,點(diǎn)擊后退鍵頭就相當(dāng)于將C出棧,此時(shí)的棧頂就是B
- 在開發(fā)程序中的“調(diào)用棧”操作系統(tǒng)棧底層就是棧的實(shí)現(xiàn)
棧的實(shí)現(xiàn)
棧是一種線性表,所以實(shí)現(xiàn)它即可使用數(shù)組,也可以使用鏈表
- 基于數(shù)組實(shí)現(xiàn)的棧—順序棧(棧頂實(shí)際就是數(shù)組尾部,在數(shù)組尾部添加和刪除)
- 基于鏈表實(shí)現(xiàn)的棧—鏈?zhǔn)綏#ㄦ湵淼念^插和尾插)
在數(shù)組尾部進(jìn)行刪除和插入的時(shí)間復(fù)雜度為O(1),所以用數(shù)組實(shí)現(xiàn)棧是我們的首選
實(shí)現(xiàn)代碼:
//基于數(shù)組實(shí)現(xiàn)的棧 public class MyStack<E> { private int size;//數(shù)組長(zhǎng)度 //實(shí)際存儲(chǔ)數(shù)據(jù)的動(dòng)態(tài)數(shù)組 private List<E> data = new ArrayList<>(); //入棧,默認(rèn)尾插 public void push(E val){ data.add(val); size ++; } //彈出棧頂元素,返回棧頂?shù)闹? public E pop(){ if(isEmpty()){ //棧為空 throw new NoSuchElementException("stack is empty!cannot pop!"); } //刪元素 E val = data.remove(size-1); size--; return val; //上面三句等同于return data.remove(size-1); } //返回棧頂元素,但不出棧 public E peek(){ if(isEmpty()){ throw new NoSuchElementException("stack is empty!cannot peek"); } return data.get(size-1); } // 判斷當(dāng)前棧是否為空 public boolean isEmpty() { return size == 0; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < size; i++) { sb.append(data.get(i)); if (i != size - 1) { // 此時(shí)還沒到棧頂,還沒到數(shù)組末尾 sb.append(", "); } } sb.append("] top"); return sb.toString(); } } //-------------------------- //測(cè)試類· public class StackTest { public static void main(String[] args) { MyStack<Integer> myStack = new MyStack<>(); myStack.push(1); myStack.push(3); myStack.push(5); System.out.println(myStack); System.out.println(myStack.pop());//刪除棧頂 System.out.println(myStack.peek());//輸出棧頂,此時(shí)棧頂為3 System.out.println(myStack.isEmpty()); } }
//輸出結(jié)果:
[1, 3, 5] top
5
3
false
隊(duì)列
只允許在一端進(jìn)行插入數(shù)據(jù)操作,在另一端進(jìn)行刪除數(shù)據(jù)操作的特殊線性表,隊(duì)列遵循先進(jìn)先出FIFO(First In First Out)的原則 :進(jìn)行插入操作的一端稱為隊(duì)尾(Tail/Rear) 出隊(duì)列:進(jìn)行刪除操作的一端稱為隊(duì)頭
其實(shí)隊(duì)列的定義很簡(jiǎn)單,就相當(dāng)于我們現(xiàn)實(shí)生活的排隊(duì)購(gòu)物,先排隊(duì)的人先結(jié)賬,也就先離開
隊(duì)列的子類比棧要復(fù)雜一些,它有:
- 基礎(chǔ)隊(duì)列—FIFO
- 基于優(yōu)先級(jí)的隊(duì)列—按照優(yōu)先級(jí)大小出隊(duì)
- 循環(huán)隊(duì)列—基于數(shù)組實(shí)現(xiàn)的
- 雙端隊(duì)列
無(wú)論是哪種隊(duì)列,都必須支持三個(gè)核心操作:
- 入隊(duì)—offer
- 出隊(duì)—poll
- 返回隊(duì)首元素—peek
基礎(chǔ)隊(duì)列的實(shí)現(xiàn)
- 基于數(shù)組實(shí)現(xiàn)的隊(duì)列—順序隊(duì)列
- 基于鏈表實(shí)現(xiàn)的隊(duì)列—鏈?zhǔn)疥?duì)列
由于隊(duì)列是從隊(duì)尾插入,隊(duì)首出隊(duì),而在數(shù)組頭部刪除的時(shí)間復(fù)雜度為O(n),此時(shí)我們用鏈表會(huì)更好一些。而且無(wú)論實(shí)現(xiàn)哪種隊(duì)列都需要覆寫三個(gè)基本操作,因此我們將隊(duì)列設(shè)計(jì)為接口
實(shí)現(xiàn)代碼:
public interface Queue<E> { // 入隊(duì) void offer(E val); // 出隊(duì) E poll(); // 返回隊(duì)首元素 E peek(); // 判斷隊(duì)列是否為空 boolean isEmpty(); } //基于鏈表實(shí)現(xiàn)的基礎(chǔ)隊(duì)列 public class MyQueue<E> implements Queue<E> { // 鏈表的每個(gè)節(jié)點(diǎn) // ------------------------------ //內(nèi)部類 private class Node { E val; Node next; public Node(E val) { this.val = val; } } // ------------------------------ // 當(dāng)前隊(duì)列中的元素個(gè)數(shù) private int size; // 隊(duì)首 private Node head; // 隊(duì)尾 private Node tail; @Override public void offer(E val) { Node node = new Node(val); if (head == null) { // 此時(shí)鏈表為空 head = tail = node; }else { tail.next = node; tail = node; } size ++; } @Override public E poll() { if (isEmpty()) { throw new NoSuchElementException("queue is empty!cannot poll!"); } E val = head.val; Node node = head; head = head.next; // 將原來(lái)頭節(jié)點(diǎn)脫鉤 node.next = null; size --; return val; } @Override public E peek() { if (isEmpty()) { throw new NoSuchElementException("queue is empty!cannot peek!"); } return head.val; } @Override public boolean isEmpty() { return size == 0; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("front ["); // 鏈表的遍歷 for (Node x = head;x != null;x = x.next) { sb.append(x.val); if (x.next != null) { // 還沒走到鏈表尾部 sb.append(", "); } } sb.append("]"); return sb.toString(); } } //測(cè)試類 public class QueueTest { public static void main(String[] args) { Queue<Integer> queue = new MyQueue<>(); queue.offer(1); queue.offer(3); queue.offer(5); System.out.println(queue); } }
作為初學(xué)者,我們不能小瞧任何簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)與算法,基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)往往作為高階數(shù)據(jù)結(jié)構(gòu)的一部分來(lái)應(yīng)用,萬(wàn)丈高樓平地起,平時(shí)要多加練習(xí),我們一起加油!
到此這篇關(guān)于Java棧和基礎(chǔ)隊(duì)列的實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Java 棧和基礎(chǔ)隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- java 數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列
- java 數(shù)據(jù)結(jié)構(gòu)中棧和隊(duì)列的實(shí)例詳解
- Java深入了解數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列的詳解
- Java 棧和隊(duì)列的相互轉(zhuǎn)換詳解
- 一起來(lái)學(xué)習(xí)Java的棧和隊(duì)列
- Java?棧與隊(duì)列實(shí)戰(zhàn)真題訓(xùn)練
- Java 棧與隊(duì)列超詳細(xì)分析講解
- Java使用跳轉(zhuǎn)結(jié)構(gòu)實(shí)現(xiàn)隊(duì)列和棧流程詳解
- Java線性結(jié)構(gòu)中棧、隊(duì)列和串的基本概念和特點(diǎn)詳解
- Java常見的數(shù)據(jù)結(jié)構(gòu)之棧和隊(duì)列詳解
- Java 棧和隊(duì)列的交互實(shí)現(xiàn)
相關(guān)文章
Kotlin基本類型自動(dòng)裝箱出現(xiàn)問題解決辦法
這篇文章主要介紹了Kotlin基本類型自動(dòng)裝箱出現(xiàn)問題解決辦法的相關(guān)資料,希望通過本文能幫助到大家,讓大家遇到這樣的問題順利解決,需要的朋友可以參考下2017-10-10struts2中simple主題下<s:fieldError>標(biāo)簽?zāi)J(rèn)樣式的移除方法
這篇文章主要給大家介紹了關(guān)于struts2中simple主題下<s:fieldError>標(biāo)簽?zāi)J(rèn)樣式的移除方法,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10Java求出任意數(shù)字的各個(gè)位數(shù)之和方式
這篇文章主要介紹了Java求出任意數(shù)字的各個(gè)位數(shù)之和方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01java保證對(duì)象在內(nèi)存中唯一性的實(shí)現(xiàn)方法
這篇文章主要介紹了java如何保證對(duì)象在內(nèi)存中的唯一性,如果創(chuàng)建多個(gè)對(duì)象的話,可能會(huì)引發(fā)出各種各樣的問題,這時(shí),就需要我們保證這個(gè)對(duì)象在內(nèi)存中的唯一性,需要的朋友可以參考下2019-06-06MyBatis插入Insert、InsertSelective的區(qū)別及使用心得
這篇文章主要介紹了MyBatis插入Insert、InsertSelective的區(qū)別及使用心得,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java分布式學(xué)習(xí)之Kafka消息隊(duì)列
Kafka是由Apache軟件基金會(huì)開發(fā)的一個(gè)開源流處理平臺(tái),由Scala和Java編寫。Kafka是一種高吞吐量的分布式發(fā)布訂閱消息系統(tǒng),它可以處理消費(fèi)者在網(wǎng)站中的所有動(dòng)作流數(shù)據(jù)2022-07-07SpringBoot實(shí)現(xiàn)登錄校驗(yàn)(JWT令牌)
JWT全稱為JSON Web Token,是一種用于身份驗(yàn)證的開放標(biāo)準(zhǔn),本文主要介紹了SpringBoot實(shí)現(xiàn)登錄校驗(yàn)(JWT令牌),具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12jvm雙親委派 vs 破壞雙親委派理解加載器的權(quán)責(zé)分配
這篇文章主要為大家介紹了jvm雙親委派 vs 破壞雙親委派對(duì)比來(lái)理解加載器的權(quán)責(zé)分配,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10