Java棧和基礎隊列的實現(xiàn)詳解
棧和隊列:都是線性表,都是基于List基礎上的實現(xiàn)
線性表:數(shù)組,鏈表,字符串,棧,隊列
元素按照一條“直線”排列,線性表這個結構中,一次添加單個元素
棧(stack)
一種特殊的線性表,其只允許在固定的一端進行插入和刪除元素操作。進行數(shù)據(jù)插入和刪除操作的一端稱為棧頂,另一端稱為棧底。棧中的數(shù)據(jù)元素遵守后進先出LIFO(Last In First Out)的原則。
棧支持的三個核心操作:
- 入棧push
- 出棧pop
- 返回棧頂元素peek
棧的常見實際應用:
- 無處不在的撤銷操作undo,一般任意的編輯器都使用 ctrl + z 操作,其實本質就是每次操作一次 ctrl + z 就是一次棧的pop
- 瀏覽器的前進后退,瀏覽器維護了一個棧結構A->B->C,此時頁面停留在C,想要回到頁面B,點擊后退鍵頭就相當于將C出棧,此時的棧頂就是B
- 在開發(fā)程序中的“調用棧”操作系統(tǒng)棧底層就是棧的實現(xiàn)
棧的實現(xiàn)
棧是一種線性表,所以實現(xiàn)它即可使用數(shù)組,也可以使用鏈表
- 基于數(shù)組實現(xiàn)的棧—順序棧(棧頂實際就是數(shù)組尾部,在數(shù)組尾部添加和刪除)
- 基于鏈表實現(xiàn)的棧—鏈式棧(鏈表的頭插和尾插)
在數(shù)組尾部進行刪除和插入的時間復雜度為O(1),所以用數(shù)組實現(xiàn)棧是我們的首選
實現(xiàn)代碼:
//基于數(shù)組實現(xiàn)的棧 public class MyStack<E> { private int size;//數(shù)組長度 //實際存儲數(shù)據(jù)的動態(tài)數(shù)組 private List<E> data = new ArrayList<>(); //入棧,默認尾插 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); } // 判斷當前棧是否為空 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ù)組末尾 sb.append(", "); } } sb.append("] top"); return sb.toString(); } } //-------------------------- //測試類· 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());//輸出棧頂,此時棧頂為3 System.out.println(myStack.isEmpty()); } }
//輸出結果:
[1, 3, 5] top
5
3
false
隊列
只允許在一端進行插入數(shù)據(jù)操作,在另一端進行刪除數(shù)據(jù)操作的特殊線性表,隊列遵循先進先出FIFO(First In First Out)的原則 :進行插入操作的一端稱為隊尾(Tail/Rear) 出隊列:進行刪除操作的一端稱為隊頭
其實隊列的定義很簡單,就相當于我們現(xiàn)實生活的排隊購物,先排隊的人先結賬,也就先離開
隊列的子類比棧要復雜一些,它有:
- 基礎隊列—FIFO
- 基于優(yōu)先級的隊列—按照優(yōu)先級大小出隊
- 循環(huán)隊列—基于數(shù)組實現(xiàn)的
- 雙端隊列
無論是哪種隊列,都必須支持三個核心操作:
- 入隊—offer
- 出隊—poll
- 返回隊首元素—peek
基礎隊列的實現(xiàn)
- 基于數(shù)組實現(xiàn)的隊列—順序隊列
- 基于鏈表實現(xiàn)的隊列—鏈式隊列
由于隊列是從隊尾插入,隊首出隊,而在數(shù)組頭部刪除的時間復雜度為O(n),此時我們用鏈表會更好一些。而且無論實現(xiàn)哪種隊列都需要覆寫三個基本操作,因此我們將隊列設計為接口
實現(xiàn)代碼:
public interface Queue<E> { // 入隊 void offer(E val); // 出隊 E poll(); // 返回隊首元素 E peek(); // 判斷隊列是否為空 boolean isEmpty(); } //基于鏈表實現(xiàn)的基礎隊列 public class MyQueue<E> implements Queue<E> { // 鏈表的每個節(jié)點 // ------------------------------ //內部類 private class Node { E val; Node next; public Node(E val) { this.val = val; } } // ------------------------------ // 當前隊列中的元素個數(shù) private int size; // 隊首 private Node head; // 隊尾 private Node tail; @Override public void offer(E val) { Node node = new Node(val); if (head == null) { // 此時鏈表為空 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; // 將原來頭節(jié)點脫鉤 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(); } } //測試類 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); } }
作為初學者,我們不能小瞧任何簡單的數(shù)據(jù)結構與算法,基礎的數(shù)據(jù)結構往往作為高階數(shù)據(jù)結構的一部分來應用,萬丈高樓平地起,平時要多加練習,我們一起加油!
到此這篇關于Java棧和基礎隊列的實現(xiàn)詳解的文章就介紹到這了,更多相關Java 棧和基礎隊列內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
struts2中simple主題下<s:fieldError>標簽默認樣式的移除方法
這篇文章主要給大家介紹了關于struts2中simple主題下<s:fieldError>標簽默認樣式的移除方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-10-10MyBatis插入Insert、InsertSelective的區(qū)別及使用心得
這篇文章主要介紹了MyBatis插入Insert、InsertSelective的區(qū)別及使用心得,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12