Java 棧與隊列超詳細(xì)分析講解
一、棧(Stack)
1、什么是棧?
棧其實就是一種數(shù)據(jù)結(jié)構(gòu) - 先進后出(先入棧的數(shù)據(jù)后出來,最先入棧的數(shù)據(jù)會被壓入棧底)

什么是java虛擬機棧?
java虛擬機棧只是JVM當(dāng)中的一塊內(nèi)存,該內(nèi)存一般用來存放 例如:局部變量當(dāng)調(diào)用函數(shù)時,我們會為函數(shù)開辟一塊內(nèi)存,叫做 棧幀,在 java虛擬機棧中開辟,具體如下。

常見考點:不可能的出棧順序

這道題該怎么分析呢?
首先我們知道,出棧時拿到的第一個元素為4,那么4必須入棧,因為入棧的順序是 1 2 3 4 5 6,所以4要入棧,1 2 3 得先入棧。(通過后面分析得知,該出棧序列正確)

2、棧的常見方法
| 方法 | 作用 |
|---|---|
| E push(E item) | 放入元素 |
| E pop() | 獲取棧頂元素并彈出 |
| E peek() | 獲取棧頂元素 |
| boolean isEmpty() | 判斷棧是否為空(父類Vector的方法) |
3、自己實現(xiàn)一個棧(底層用一個數(shù)組實現(xiàn))
public class MyStack {
public int[] elem;
public int usedSize;
public MyStack() {
this.elem = new int[4];
}
// 放入元素
public void push(int val) {
if(isFull()) {
// 如果放滿了,二倍擴容
this.elem = Arrays.copyOf(elem,2 * elem.length);
}
this.elem[this.usedSize++] = val;
}
// 獲取棧頂元素并彈出
public int pop() {
if (isEmpty()) {
throw new RuntimeException("棧為空!");
}
usedSize--;
return elem[usedSize];
}
// 獲取棧頂元素
public int peek() {
if (isEmpty()) {
throw new RuntimeException("棧為空!");
}
return elem[usedSize-1];
}
// 是否為空
public boolean isEmpty() {
return usedSize == 0;
}
// 是否滿了
public boolean isFull() {
return elem.length == usedSize;
}
}
二、隊列(Queue)
1、什么是隊列?
只允許在一端進行插入數(shù)據(jù)操作,在另一端進行刪除數(shù)據(jù)操作的特殊線性表,隊列具有 - 先進先出。
入隊列:進行插入操作的一端稱為隊尾
出隊列:進行刪除操作的一端稱為隊頭


2、隊列的常見方法


// 普通隊列 Queue<Integer> queue = new LinkedList<>(); queue.offer(1);// 隊尾入 int top = queue.peek();// 獲取隊頭元素 queue.poll();// 彈出隊尾元素并返回 // 雙端隊列 Deque<Integer> deque = new LinkedList<>(); deque.offer(1);// 默認(rèn)隊尾入 deque.offerFirst(2);// 隊頭入 deque.offerLast(3);// 隊尾入 deque.peekFirst();// 獲取隊頭元素 deque.peekLast();// 獲取隊尾元素 deque.pollFirst();// 彈出隊頭元素并返回 deque.pollLast();// 彈出隊尾元素并返回
3、隊列的實現(xiàn)(單鏈表實現(xiàn))

/**
* 每個節(jié)點
*/
class Node{
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
}
public class MyQueue {
public Node head;
public Node tail;
/**
* 插入元素 -- 尾插法
* @param val
*/
public void offer(int val) {
Node node = new Node(val);
if (head == null) {
head = node;
tail = node;
}else {
tail.next = node;
tail = tail.next;
}
}
/**
* 出隊列
*/
public int poll() {
if(isEmpty()) {
throw new RuntimeException("隊列為空!");
}
int val = head.val;
head = head.next;
return val;
}
/**
* 獲取隊頭元素
*/
public int peek() {
if(isEmpty()) {
throw new RuntimeException("隊列為空!");
}
return head.val;
}
// 隊列是否為空
public boolean isEmpty() {
return head == null;
}
}
4、循環(huán)隊列
當(dāng)考慮用數(shù)組來實現(xiàn)一個隊列, 很容易想到以下結(jié)構(gòu):

當(dāng)我們連續(xù)從該隊頭中彈出元素時,就可以發(fā)現(xiàn)問題了

可以看到此時數(shù)組并沒有滿,但是當(dāng)我們再次插入元素時,隊尾卻插入不了了,這時候我們可以想到將該數(shù)組看成是循環(huán)的數(shù)組,結(jié)構(gòu)如下。

可以看出,當(dāng) front 和 rear 相遇時,隊列可能的情況有兩種,要么為空,要么是滿的狀態(tài)。那么隊列什么時候為空,什么時候是滿的呢?
我們有兩種方法:
1、設(shè)置usedSize 當(dāng)usedSize和數(shù)組長度相等時為滿,等于0 則為空。
2、設(shè)置標(biāo)志位 設(shè) flag = true,每放一個元素,將 flag 置為 false,每有一個元素出隊列,則將 flag 置為 true。當(dāng) front 和 rear 相遇時,flag為 true 則是空的,反之則是滿的。
public class MyCircularQueue {
public int[] elem;
public int front;// 隊頭下標(biāo)
public int rear;// 隊尾下標(biāo)
boolean flag = true;// 是否為空
public MyCircularQueue(int k) {
elem = new int[k];
}
// 向循環(huán)隊列插入一個元素。如果成功插入則返回真。
public boolean enQueue(int value) {
if (isFull()) {
return false;
// throw new RuntimeException("隊列已滿!");
}
elem[rear] = value;
rear = (rear + 1) % elem.length;
flag = false;
return true;
}
// 從循環(huán)隊列中刪除一個元素。如果成功刪除則返回真。
public boolean deQueue() {
if (isEmpty()) {
return false;
// throw new RuntimeException("隊列為空!");
}
front = (front + 1) % elem.length;
flag = true;
return true;
}
// 從隊首獲取元素。如果隊列為空,返回 -1 。
public int Front() {
if (isEmpty()) {
return -1;
// throw new RuntimeException("隊列為空!");
}
return elem[front];
}
// 獲取隊尾元素。如果隊列為空,返回 -1 。
public int Rear() {
if (isEmpty()) {
return -1;
// throw new RuntimeException("隊列為空!");
}
// 如果是0下標(biāo),拿最后一個元素
if (rear == 0) {
return elem[elem.length-1];
}else {
return elem[rear - 1];
}
}
// 檢查循環(huán)隊列是否為空。
public boolean isEmpty() {
if (rear == front && flag){
return true;
}
return false;
}
// 檢查循環(huán)隊列是否已滿。
public boolean isFull() {
if (rear == front && !flag){
return true;
}
return false;
}
}
到此這篇關(guān)于Java 棧與隊列超詳細(xì)分析講解的文章就介紹到這了,更多相關(guān)Java 棧與隊列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- java 數(shù)據(jù)結(jié)構(gòu)之棧與隊列
- java 數(shù)據(jù)結(jié)構(gòu)中棧和隊列的實例詳解
- Java深入了解數(shù)據(jù)結(jié)構(gòu)之棧與隊列的詳解
- Java 棧和隊列的相互轉(zhuǎn)換詳解
- Java棧和基礎(chǔ)隊列的實現(xiàn)詳解
- 一起來學(xué)習(xí)Java的棧和隊列
- Java?棧與隊列實戰(zhàn)真題訓(xùn)練
- Java使用跳轉(zhuǎn)結(jié)構(gòu)實現(xiàn)隊列和棧流程詳解
- Java線性結(jié)構(gòu)中棧、隊列和串的基本概念和特點詳解
- Java常見的數(shù)據(jù)結(jié)構(gòu)之棧和隊列詳解
- Java 棧和隊列的交互實現(xiàn)
相關(guān)文章
Java中ThreadLocal避免內(nèi)存泄漏的方法詳解
ThreadLocal是Java中的一個線程本地存儲機制,它允許每個線程擁有一個獨立的本地存儲空間,用于存儲該線程的變量,本文主要介紹了ThreadLocal如何避免內(nèi)存泄漏,需要的朋友可以參考下2023-05-05
如何使用HttpClient發(fā)送java對象到服務(wù)器
這篇文章主要介紹了如何使用HttpClient發(fā)送java對象到服務(wù)器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11
Java lombok中@Accessors注解三個屬性的作用
這篇文章主要介紹了Java?lombok的@Accessors注解屬性解析,該注解主要作用是:當(dāng)屬性字段在生成?getter?和?setter?方法時,做一些相關(guān)的設(shè)置,需要的朋友可以參考下2023-05-05
Java中String的JdbcTemplate連接SQLServer數(shù)據(jù)庫的方法
這篇文章主要介紹了Java中String的JdbcTemplate連接SQLServer數(shù)據(jù)庫的方法,在研發(fā)過程中我們需要與其他系統(tǒng)對接的場景,連接SQLServer拉取數(shù)據(jù),所以就用jdbc連接數(shù)據(jù)庫的方式連接外部數(shù)據(jù)源,需要的朋友可以參考下2021-10-10
MyBatis-Plus更新對象時將字段值更新為null的四種常見方法
MyBatis-Plus 是一個 MyBatis 的增強工具,在簡化開發(fā)、提高效率方面表現(xiàn)非常出色,而,在使用 MyBatis-Plus 更新對象時,默認(rèn)情況下是不會將字段值更新為 null 的,如果你需要將某些字段的值更新為 null,有幾種方法可以實現(xiàn),本文將介紹幾種常見的方法2024-11-11
Linux環(huán)境下的Java(JDBC)連接openGauss數(shù)據(jù)庫實踐記錄
這篇文章主要介紹了Linux環(huán)境下的Java(JDBC)連接openGauss數(shù)據(jù)庫實踐記錄,需要的朋友可以參考下2022-11-11
Intellij idea 代碼提示忽略字母大小寫和常用快捷鍵及設(shè)置步驟
這篇文章主要介紹了Intellij idea 代碼提示忽略字母大小寫和常用快捷鍵及設(shè)置步驟,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-02-02

