Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之棧和隊(duì)列
一、棧
1.1 概述
Java為什么要有集合類: 臨時(shí)存儲(chǔ)數(shù)據(jù)。
鏈表的本質(zhì): 對(duì)象間通過(guò)持有和引用關(guān)系互相關(guān)聯(lián)起來(lái)。
線性表: 普通線性表, 操作受限線性表(某些操作受到限制 --> 某一個(gè)線性表它的增刪改操作受到限制) --> 棧 & 隊(duì)列
1.1.1 線性表的概念
(1)線性表:n個(gè)數(shù)據(jù)元素的有序序列。
①首先,線性表中元素的個(gè)數(shù)是有限的。
②其次,線性表中元素是有序的。
(2)那這個(gè)”序”指的是什么呢?
①除表頭和表尾元素外,其它元素都有唯一前驅(qū)和唯一后繼,其唯一前驅(qū)或唯一后繼確定了該元素在線性表中的位置。
②因此,線性表中,每個(gè)數(shù)據(jù)元素都有一個(gè)確定的位序,這個(gè)確定的位序我們稱之為索引。 表頭元素有唯一后繼,無(wú)前驅(qū),表尾元素有唯一前驅(qū),無(wú)后繼。
1.1.2 棧的概念
棧是一種”操作受限”的線性表,體現(xiàn)在只能在一端插入和刪除數(shù)據(jù),符合FILO的特性。
FILO: 先進(jìn)后出,
LIFO: 后進(jìn)先出
1.1.3 棧的應(yīng)用
線性表和哈希表在以后工作中會(huì)最常用。
棧在實(shí)際工作中不常用
應(yīng)用場(chǎng)景:
1.函數(shù)調(diào)用棧
2.反序字符串: 實(shí)現(xiàn)reNumber(str)方法,反轉(zhuǎn)字符串(附代碼) 。
public class DemoStack1 { public static void main(String[] args) { String str = "123456789"; String reStr = reStr(str); System.out.println(reStr); } // 棧先進(jìn)后出 public static String reStr(String str){ MyArrayStack<Character> stack = new MyArrayStack<>(); for (int i = 0; i < str.length(); i++) { stack.push(str.charAt(i)); } StringBuffer buffer = new StringBuffer(); // 1 2 3 4 5 6 7 8 9 while (!stack.isEmpty()){ Character pop = stack.pop(); buffer.append(pop); } return buffer.toString(); } }
3.括號(hào)匹配問(wèn)題: 實(shí)現(xiàn)judgeBracket(str)方法來(lái)判斷括號(hào)匹配 (附代碼)。
public class DemoStack2 { public static void main(String[] args) { String str = "public class) DemoStack2 {public static void main(String[] args) {}}"; boolean bool = judgeBracket(str); System.out.println(bool); } public static boolean judgeBracket(String str){ MyArrayStack<Character> stack = new MyArrayStack<>(); for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); // 判斷c 是left括號(hào), 然后入棧 if (c == '{'){ stack.push('}'); } else if (c == '['){ stack.push(']'); }else if (c == '('){ stack.push(')'); } else if (c == '}' || c == ')' || c == ']'){ Character pop = stack.pop(); if (c != pop){// 不匹配 return false; } } } return stack.isEmpty(); } }
4.編譯器利用棧實(shí)現(xiàn)表達(dá)式求值
5.瀏覽器的前進(jìn)后退功能
6. 利用棧實(shí)現(xiàn) DFS: depth-first-search 深度優(yōu)先遍歷(樹(shù) 圖)
編譯器利用棧實(shí)現(xiàn)表達(dá)式求值
中綴表達(dá)式: 2 + 3 * 2 給人看的 , 運(yùn)算符放到中間
前綴表達(dá)式: + 2 * 3 2 運(yùn)算符放到之前
后綴表達(dá)式: 2 3 2 * + 運(yùn)算符放到后面
// 中綴表達(dá)式轉(zhuǎn)化為后綴:
// 遍歷中綴表達(dá)式
// 遇到操作數(shù)輸出
// 遇到操作符, 出棧, 直到遇到更低優(yōu)先級(jí)的操作符, 操作符入棧
// 遍歷完成, 全部彈棧
// 中綴表達(dá)式轉(zhuǎn)化為前綴:
// 遍歷中綴表達(dá)式: 逆序遍歷
// 遇到操作數(shù)輸出: 頭插法
// 遇到操作符, 出棧, 只彈出更高優(yōu)先級(jí)的操作符, 操作符入棧
// 遍歷完成, 全部彈棧
二、隊(duì)列
2.1 隊(duì)列的概念
隊(duì)列也是一種”操作受限”的線性表,體現(xiàn)在一端插入數(shù)據(jù)在另一端刪除數(shù)據(jù),特性是FIFO。
2.2 隊(duì)列的實(shí)現(xiàn)
實(shí)現(xiàn)一個(gè)集合類
集合類: 數(shù)據(jù)容器
底層: 數(shù)組 or 鏈表
數(shù)據(jù)結(jié)構(gòu)表現(xiàn): 隊(duì)列
(1)用數(shù)組實(shí)現(xiàn)一個(gè)隊(duì)列。
/** * 用數(shù)組實(shí)現(xiàn)一個(gè)隊(duì)列 * 集合類角度: 數(shù)據(jù)容器 * 底層: 數(shù)組 * 表示: 隊(duì)列 */ public class MyArrayQueue <T> { private final int MAX_CAPACITY = Integer.MAX_VALUE - 8; private final int INIT_CAPACITY = 16; private Object[] objs; private int size; private int head;// 頭的下標(biāo) private int end;// 尾的下標(biāo) public MyArrayQueue(){ objs = new Object[INIT_CAPACITY]; } public MyArrayQueue(int initCapcity){ if (initCapcity <= 0 || initCapcity > MAX_CAPACITY) throw new IllegalArgumentException("" + initCapcity); objs = new Object[initCapcity]; } public boolean offer(T t){ // 如果數(shù)組滿了 if (size == objs.length){ int newLen = getLen(); grow(newLen); } // 可以添加 if (isEmpty()){ // 沒(méi)有任何元素存儲(chǔ): 新添加的元素就是唯一的元素 objs[head] = t; end = head; size++; return true; } else { // 原本存儲(chǔ)就有內(nèi)容 // 尾后移一位 end = (end + 1) % objs.length; objs[end] = t; size++; return true; } } private void grow(int newLen) { Object[] newArr = new Object[newLen]; for (int i = 0; i < objs.length; i++) { int index = (head + i) % objs.length; newArr[i] = objs[index]; } objs = newArr; head = 0; end = size - 1; } private int getLen() { int oldLen = objs.length; int newLen = oldLen << 1; // 判斷新長(zhǎng)度是否溢出 if (newLen <= 0 || newLen > MAX_CAPACITY){ newLen = MAX_CAPACITY; } // 如果新長(zhǎng)度和舊長(zhǎng)度一樣 if (newLen == oldLen)throw new RuntimeException("stack can not add"); return newLen; } public T poll(){ if (isEmpty()) throw new RuntimeException("queue is empty"); if (size == 1){ // 原隊(duì)列中只剩一個(gè)元素 T oldValue = (T)objs[head]; head = 0; end = 0; size--; return oldValue; } else { // 隊(duì)列中超過(guò)一個(gè)元素 T oldValue = (T)objs[head]; head = (head + 1) % objs.length; size--; return oldValue; } } public T peek(){ if (isEmpty()) throw new RuntimeException("queue is empty"); return (T)objs[head]; } public int size() { return size; } public boolean isEmpty(){ return size == 0; } }
(2)用鏈表實(shí)現(xiàn)一個(gè)鏈表。
public class MyLinkedQueue <T> { private Node head;// 隊(duì)頭 private Node end; // 隊(duì)尾 private int size; // 添加 offer // 刪除 poll // 查看隊(duì)頭元素 peek public boolean offer(T t){ // 如果原隊(duì)列為空 if (isEmpty()){// 原隊(duì)列空 // 讓頭尾都指向這個(gè)新加的結(jié)點(diǎn) head = new Node(t, null); end = head; size++; return true; } // 原隊(duì)列不空 // 把這個(gè)元素添加到隊(duì)尾 end.next = new Node(t, null); end = end.next;// end后移 size++; return true; } public T poll(){ if (isEmpty()) throw new RuntimeException("queue is empty"); if (size == 1){ // 代表著, 鏈表中只有一個(gè)元素 T oldVlaue = head.value; head = null; end = null; size--; return oldVlaue; }else { T oldVlaue = head.value; head = head.next; size--; return oldVlaue; } } public T peek(){ if (isEmpty()) throw new RuntimeException("queue is empty"); return head.value; } public boolean isEmpty(){ return size == 0; } public int size(){ return size; } class Node{ T value; Node next; public Node(T value, Node next) { this.value = value; this.next = next; } } }
2.3 隊(duì)列的應(yīng)用
(1)隊(duì)列更不常用(自己寫代碼使用不常用):
(2)常見(jiàn), 很多jdk源碼, 中間件的源碼上 很多地方使用了隊(duì)列
Eg:
①生產(chǎn)者消費(fèi)者問(wèn)題
生產(chǎn)者 – 消費(fèi)者
生產(chǎn)者: 廚師
消費(fèi)者: 吃面包的人
桌子: 放面包的地方
②線程池
線程池: 任務(wù)
生產(chǎn)者: 產(chǎn)生任務(wù)
消費(fèi)者: 線程
桌子: 隊(duì)列
③生態(tài)環(huán)境:
第三方輪子: 要看懂
Maven
④消息隊(duì)列和緩存。
(3)普通隊(duì)列的應(yīng)用場(chǎng)景是很有限的,一般在工程中用到的是阻塞隊(duì)列。
①阻塞隊(duì)列(有一個(gè)隊(duì)列, 大小一定):常用于生產(chǎn)者-消費(fèi)者模型中。
當(dāng)隊(duì)列滿的時(shí)候,入隊(duì)列就阻塞。
當(dāng)隊(duì)列空的時(shí)候,出隊(duì)列就阻塞。
②利用隊(duì)列實(shí)現(xiàn) BFS:breadth first search 廣度優(yōu)先搜索/ 遍歷 ()
到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之棧和隊(duì)列的文章就介紹到這了,更多相關(guān)Java棧和隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java 棧和隊(duì)列的相互轉(zhuǎn)換詳解
- Java深入了解數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列的詳解
- Java數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列實(shí)例詳解
- Java數(shù)據(jù)結(jié)構(gòu)專題解析之棧和隊(duì)列的實(shí)現(xiàn)
- Java特性隊(duì)列和棧的堵塞原理解析
- 如何使用兩個(gè)棧實(shí)現(xiàn)隊(duì)列Java
- Java數(shù)據(jù)結(jié)構(gòu)之鏈表、棧、隊(duì)列、樹(shù)的實(shí)現(xiàn)方法示例
- Java編程用兩個(gè)棧實(shí)現(xiàn)隊(duì)列代碼分享
- Java棧和基礎(chǔ)隊(duì)列的實(shí)現(xiàn)詳解
相關(guān)文章
mybatis中<if>標(biāo)簽bool值類型為false判斷方法
這篇文章主要給大家介紹了關(guān)于mybatis中<if>標(biāo)簽bool值類型為false判斷方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用mybatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08在mybatis中使用mapper進(jìn)行if條件判斷
這篇文章主要介紹了在mybatis中使用mapper進(jìn)行if條件判斷,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01解決mybatisplus MetaObjectHandler 失效的問(wèn)題
本文主要介紹了解決mybatisplus MetaObjectHandler 失效的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02Mybatis?saveAndUpdate空值不更新問(wèn)題及解決
這篇文章主要介紹了Mybatis?saveAndUpdate空值不更新問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02在?Spring?Boot?中使用?Quartz?調(diào)度作業(yè)的示例詳解
這篇文章主要介紹了在?Spring?Boot?中使用?Quartz?調(diào)度作業(yè)的示例詳解,在本文中,我們將看看如何使用Quartz框架來(lái)調(diào)度任務(wù),Quartz支持在特定時(shí)間運(yùn)行作業(yè)、重復(fù)作業(yè)執(zhí)行、將作業(yè)存儲(chǔ)在數(shù)據(jù)庫(kù)中以及Spring集成,需要的朋友可以參考下2022-07-07Java JDK 動(dòng)態(tài)代理的使用方法示例
Java 動(dòng)態(tài)代理機(jī)制以巧妙的方式近乎完美地實(shí)踐了代理模式的設(shè)計(jì)理念。下面這篇文章主要給大家分享了關(guān)于Java JDK 動(dòng)態(tài)代理的使用方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-07-07基于Java解決華為機(jī)試實(shí)現(xiàn)密碼截取?
這篇文章主要介紹了基于Java解決華為機(jī)試實(shí)現(xiàn)密碼截取,文章圍繞主題相關(guān)資料展開(kāi)詳細(xì)內(nèi)容,具有一的參考價(jià)值,需要的小伙伴可以參考一下,希望對(duì)你有所幫助2022-02-02