一、棧
1、描敘
棧和隊列是計算機中基本的兩個數據結構,棧可以達到後進先出,隊列可以先進先出。在實際應用上,我們可以使用棧進行逆序遍歷鏈表,非遞歸中序遍歷二叉樹,括號匹配,函數調用等等;可以使用隊列對二叉樹進行層次遍歷,打印機的打印服務,通信中的消息隊列等等。
棧的儲存規則:
1,棧只能從表的一端存取數據,另一端是封閉的
2,在棧中,無論是存數據還是取數據,都必須遵循"先進後出"的原則,即最先進棧的元素最後出棧。
棧的使用案例1:
瀏覽器 “回退” 功能的實現,底層使用的就是棧存儲結構。
當你關閉頁面 A 時,瀏覽器會將頁面 A 入棧;同樣,當你關閉頁面 B 時,瀏覽器也會將 B入棧。因此,當你執行回退操作時,纔會首先看到的是頁面 B,然後是頁面 A,這是棧中數據依次出棧的效果。
棧的使用案例2:
棧存儲結構還可以幫我們檢測代碼中的括號匹配問題。
多數編程語言都會用到括號(小括號、中括號和大括號),括號的錯誤使用(通常是丟右括號)會導致程序編譯錯誤,而很多開發工具中都有檢測代碼是否有編輯錯誤的功能,其中就包含檢測代碼中的括號匹配問題,此功能的底層實現使用的就是棧結構。
2、圖文示例
先進後出
3、代碼示例
package stackAndQueue;
/**
* TODO 棧,先進後出
*/
public class Stack {
// 底層基於數組
private int[] arr;
// 數據長度, 最後一個數據的索引=數據長度-1
private int size;
// 容量設置
public Stack() {
arr = new int[16];
}
public Stack(int length) {
arr = new int[length];
}
/**
* 添加
*/
public void plus(int val) {
arr[size++] = val;
}
/**
* 獲取並彈出元素, 最後一個數據的索引=size-1
*/
public int pop() {
return arr[--size];
}
/**
* 判斷是否爲空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 容量是否滿了,添加可先判斷容量,進行擴容操作
*/
public boolean isFull() {
return size == arr.length;
}
}
測試代碼
// 測試
class Test {
public static void main(String[] args) {
Stack stack = new Stack(5);
stack.plus(1);
stack.plus(2);
stack.plus(3);
stack.plus(4);
stack.plus(5);
System.out.println("容量是否滿了-->" + stack.isFull());
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
}
// 輸出
容量是否滿了-->true
5
4
3
2
1
二、隊列
1、描敘
隊列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱爲隊尾,進行刪除操作的端稱爲隊頭。隊列中沒有元素時,稱爲空隊列。
隊列的數據元素又稱爲隊列元素。在隊列中插入一個隊列元素稱爲入隊,從隊列中刪除一個隊列元素稱爲出隊。因爲隊列只允許在一端插入,在另一端刪除,所以只有最早進入隊列的元素才能最先從隊列中刪除,故隊列又稱爲先進先出(FIFO—first in first out)線性表。 [1]
隊列的實現
隊列存儲結構的實現有以下兩種方式:
順序隊列:在順序表的基礎上實現的隊列結構;
鏈隊列:在鏈表的基礎上實現的隊列結構;
兩者的區別僅是順序表和鏈表的區別,即在實際的物理空間中,數據集中存儲的隊列是順序隊列,分散存儲的隊列是鏈隊列。
隊列的實際應用
實際生活中,隊列的應用隨處可見,比如排隊買 XXX、醫院的掛號系統等,採用的都是隊列的結構。
拿排隊買票來說,所有的人排成一隊,先到者排的就靠前,後到者只能從隊尾排隊等待,隊中的每個人都必須等到自己前面的所有人全部買票成功並從隊頭出隊後,才輪到自己買票。這就不是典型的隊列結構嗎?
2、圖文示例
普通隊列
先進先出
循環隊列
先進先出
3、代碼示例
package stackAndQueue;
/**
* TODO 隊列,先進先出
*/
public class Queue {
// 底層基於數組
private int[] arr;
// 數據長度
private int size;
// 開頭元素索引 (每獲取一次數據 front+1)
private int front;
// 結尾元素索引(每添加一次數據rear+1,每獲取一次數據rear-1 )--> 數據長度=rear+1
private int rear;
// 容量設置
public Queue() {
arr = new int[16];
front = -1;
rear = -1;
}
public Queue(int length) {
arr = new int[length];
front = -1;
rear = -1;
}
/**
* 獲取當前數據長度
*/
public int size() {
return this.size;
}
/**
* 插入元素
*/
public void plus(int val) {
// 判斷數組是否滿了
if (isFull()) {
System.out.println("插入["+val+"]失敗,數組容量已滿");
} else {
// 循環插入,--元素尾添加
if (rear == arr.length - 1) {
rear = -1;
}
size++;
arr[++rear] = val;
}
}
/**
* 獲取並彈出元素
*/
public int pop() {
// 循環讀取--元素頭開始讀取
if (front == arr.length - 1) {
front = -1;
}
size--;
return arr[++front];
}
/**
* 判斷元素是否爲空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 容量是否滿了,添加可先判斷容量,進行擴容操作
*/
public boolean isFull() {
return size == arr.length;
}
}
測試代碼
// 測試
class Test1 {
public static void main(String[] args) {
Queue queue = new Queue(5);
queue.plus(1);
queue.plus(2);
queue.plus(3);
queue.plus(4);
queue.plus(5);
System.out.println("容量是否滿了-->" + queue.isFull() + " 當前數據長度:" + queue.size());
//消費--> size=0
while (!queue.isEmpty()) {
System.out.println(queue.pop());
}
// 添加數據,size=0
queue.plus(6);
queue.plus(7);
queue.plus(8);
queue.plus(9);
queue.plus(10);
System.out.println("彈出--> " + queue.pop());
queue.plus(11);
//
queue.plus(12);
queue.plus(13);
queue.plus(14);
while (!queue.isEmpty()) {
System.out.println(queue.pop());
}
}
}
// 打印
容量是否滿了-->true 當前數據長度:5
1
2
3
4
5
彈出--> 6
插入[12]失敗,數組容量已滿
插入[13]失敗,數組容量已滿
插入[14]失敗,數組容量已滿
7
8
9
10
11
本文到此結束,如果覺得有用,勞煩各位點贊關注一下唄,將不定時持續更新更多的內容…,感謝大家的觀看!