老生常談Java中的棧和隊(duì)列
一、??棧(Stack)
1.??什么是棧?
??棧
棧是一種數(shù)據(jù)結(jié)構(gòu),他是一種只允許在一端固定進(jìn)行插入和刪除操作的特殊線性表。先進(jìn)入的數(shù)據(jù)被壓入棧底,最后進(jìn)入的數(shù)據(jù)被放在棧頂,需要讀出的數(shù)據(jù)從棧頂開始彈出,按照先入后出的原則。

操作:
入棧:也稱為壓棧/進(jìn)棧,將插入的元素放在棧頂;
出棧: 將棧頂的元素進(jìn)行刪除;
??棧的特點(diǎn)
- 操作受限性:只允許在一端固定進(jìn)行插入和刪除操作,不像順序表可以進(jìn)行任意的插入和刪除;
- 數(shù)據(jù)存儲(chǔ)的有序性:元素遵循先進(jìn)后出的原則,即先入棧的元素后出棧;
- 空間效率:無需像數(shù)組等數(shù)據(jù)結(jié)構(gòu)分配存儲(chǔ)大量的固定空間,可以根據(jù)元素的入棧和出棧發(fā)生動(dòng)態(tài)變化,可以避免空間的浪費(fèi);
- 時(shí)間復(fù)雜度:出棧和出棧的時(shí)間復(fù)雜度都為O(1),操作效率高;
2.??棧的使用
棧的方法

| 方法 | 功能 |
| Stack() | 構(gòu)造一個(gè)空的棧 |
| E push(E e) | 將元素入棧 |
| E pop() | 將元素出棧 |
| E peek() | 獲取棧頂元素 |
| int size() | 獲取棧中有效個(gè)數(shù)大小 |
| boolean empty() | 判斷棧是否為空 |
細(xì)心的同學(xué)觀察圖片和表格中的方法會(huì)發(fā)現(xiàn),圖片中并沒有size方法,是因?yàn)?strong>Stack繼承于Vector,他使用的size方法是Vector中的方法;
什么是Vector?
- Vector繼承與List接口,他與ArrayList相似,與ArrayList不同的是,Vector是線程安全,當(dāng)其相對性能較低。在當(dāng)線程的情況下,如果不需要線程安全,更推薦ArrayList。
什么是線程安全?
- 線程安全指的是在多線程的環(huán)境下,程序或代碼能過正確地運(yùn)行,不會(huì)出現(xiàn)數(shù)據(jù)不一致、競爭條件、死鎖等問題。
方法的使用:
public static void main(String[] args) {
Stack<Integer> stack=new Stack<>();
//入棧
stack.push(1);
stack.push(2);
stack.push(3);
//獲取有效個(gè)數(shù)大小
System.out.println(stack.size());//3
//獲取棧頂元素
System.out.println(stack.peek());//3
//出棧
stack.pop();
//獲取棧頂元素
System.out.println(stack.peek());//2
//查找元素下標(biāo)
System.out.println(stack.search(2));
}3.??棧的模擬實(shí)現(xiàn)
//數(shù)組模擬實(shí)現(xiàn)棧
public class MyStack {
//元素
public int[] n;
//有效元素大小
public int usedsize;
//構(gòu)造方法
public MyStack(int[] n) {
this.n = n;
}
//入棧:將元素進(jìn)行插入
//1.判斷是否滿了,滿了用Arrays.copyOf進(jìn)行擴(kuò)容
//1.用元素放入數(shù)組中,
//2.元素個(gè)數(shù)增加
public void push(int x){
if(isFull()){
this.n= Arrays.copyOf(n,2*n.length);
}
n[usedsize]=x;
usedsize++;
}
private boolean isFull(){
return usedsize==n.length;
}
//出棧:將棧頂元素拿出
//1.判斷棧是否為空;
// 2.將棧中元素減減即可
public int pop(){
if(empty()){
return -1;
}
int val=n[usedsize-1];
usedsize--;
return val;
}
//獲取棧頂元素
//1.判斷棧是否為空,如果為空拋出異常
// 2.獲取棧中元素
public int peek(){
if(empty()){
throw new EmptyStackException();
}
return n[usedsize-1];
}
//判斷棧是否為空
//看其有效個(gè)數(shù)是否為0
public boolean empty()throws EmptyStackException{
return this.usedsize==0;
}
}可以通過鏈表來模擬實(shí)現(xiàn)棧嗎?
答案是:可以的;
1.如果采用單鏈表來實(shí)現(xiàn):
- 采用的是頭插法,入棧和出棧的時(shí)間復(fù)雜度都為O(1);
- 采用的是尾插法,入棧的時(shí)間復(fù)雜度為O(n),如果有l(wèi)ast,那么時(shí)間復(fù)雜度為O(1),但是出棧時(shí)間復(fù)雜度一定是O(n);
2.如果采用雙鏈表來實(shí)現(xiàn):
- 不管是頭插法和尾插法都可以實(shí)現(xiàn);
4.??棧的優(yōu)缺點(diǎn)
??優(yōu)點(diǎn):
- 數(shù)據(jù)存儲(chǔ)的有序性:元素遵循先進(jìn)后出的原則,即先入棧的元素后出棧;
- 操作簡單高效:棧的入棧和出棧操作都在棧頂進(jìn)行,時(shí)間復(fù)雜度在為O(1),能迅速實(shí)現(xiàn)插入和刪除;
- 空間效率:無需像數(shù)組等數(shù)據(jù)結(jié)構(gòu)分配存儲(chǔ)大量的固定空間,可以根據(jù)元素的入棧和出棧發(fā)生動(dòng)態(tài)變化,可以避免空間的浪費(fèi);
??缺點(diǎn):
- 功能有限:功能比較單一,只能在一端進(jìn)行簡單的插入和刪除;
- 數(shù)據(jù)訪問有限:除棧頂元素外,訪問其他元素需要一一彈出,操作麻煩且效率低;
- 存儲(chǔ)容量問題:雖然可以動(dòng)態(tài)擴(kuò)容,但是在大量元素入棧的時(shí)候,棧的連續(xù)空間可能受內(nèi)存限制;
二、??隊(duì)列(Queue)
1.??什么是隊(duì)列?
??隊(duì)列
隊(duì)列就像日常生活中的排隊(duì)一樣,一端用于插入元素,稱為隊(duì)尾;另一端用于刪除元素,稱為隊(duì)頭。其遵循的的是先進(jìn)先出的原則。

操作:
- 入隊(duì):插入元素在隊(duì)尾;
- 出隊(duì): 刪除元素在隊(duì)頭;
??隊(duì)列的特點(diǎn)
- 順序性:隊(duì)列按照先進(jìn)先出的原則;
- 操作受限性:隊(duì)列主要集中于隊(duì)頭和隊(duì)尾;
- 存儲(chǔ)結(jié)構(gòu)的多樣性:隊(duì)列可以通過不同的存儲(chǔ)結(jié)構(gòu)來實(shí)現(xiàn),常見的有數(shù)組和鏈表;
- 并發(fā)處理優(yōu)勢:在多線程或多任務(wù)環(huán)境中,隊(duì)列常用于實(shí)現(xiàn)數(shù)據(jù)的緩沖和同步;
- 空間利用效率:可以實(shí)現(xiàn)空間的動(dòng)態(tài)調(diào)整,提高空間的利用效率,避免空間浪費(fèi);
隊(duì)列的分類
- 普通隊(duì)列:普通隊(duì)列是隊(duì)列最基本的形式,遵循先進(jìn)先出的原則;

- 雙端隊(duì)列(Dequeue):雙端隊(duì)列允許兩端進(jìn)行插入和刪除操作,元素可以從隊(duì)頭出隊(duì)和入隊(duì);

- 循環(huán)隊(duì)列:循環(huán)列隊(duì)是將隊(duì)列存儲(chǔ)空間的最后一個(gè)位置繞到第一個(gè)位置,形成邏輯上的閉環(huán);

- 優(yōu)先隊(duì)列: 優(yōu)先級隊(duì)列中帶有優(yōu)先級元素,入隊(duì)時(shí)按照優(yōu)先級確定在隊(duì)列中的位置,出隊(duì)時(shí)總是優(yōu)先級最高的元素先出隊(duì);這個(gè)得在二叉樹學(xué)完才明白;
2.??隊(duì)列的使用
??實(shí)例化
Queue是一個(gè)接口,不能實(shí)例化本身,但只要實(shí)現(xiàn)了這個(gè)接口都可以實(shí)例化,比如LinkedList、ArrayDeque以及PriorityQueue等等其他;
public static void main(String[] args) {
Queue<Integer> queue=new LinkedList<>();
Queue<Integer> queue1=new ArrayDeque<>();
Queue<Integer> queue2=new PriorityQueue<>();
}??Queue中的方法

看下面的圖片,我們可以發(fā)現(xiàn)他們分為兩類使用效果相同,但是使用目的不同:


| 方法 | 功能 |
| boolean offer(E e) | 入列隊(duì) |
| E poll() | 出列隊(duì) |
| peek() | 獲取隊(duì)頭元素 |
| int size() | 有效元素個(gè)數(shù) |
| boolean isEmpty() | 判斷是否為空 |
??隊(duì)列的使用
public static void main(String[] args) {
Queue<Integer> queue=new LinkedList<>();
//入隊(duì)
queue.offer(1);
queue.offer(2);
queue.offer(3);
//獲取有效元素個(gè)數(shù)
System.out.println(queue.size());//3
//獲取隊(duì)頭元素
System.out.println(queue.peek());//1
//出隊(duì)
System.out.println(queue.poll());//1
}3.??隊(duì)列模擬實(shí)現(xiàn)
普通隊(duì)列用雙鏈表模擬實(shí)現(xiàn):
public class MyQueue {
//創(chuàng)建節(jié)點(diǎn)類
static class ListNode{
public int val;
public ListNode prev;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public ListNode first=null;
public ListNode last=null;
public int usedSize=0;
//入隊(duì)
//判斷是否為空,如果為空將頭尾節(jié)點(diǎn)都等于該新節(jié)點(diǎn)
//如果不是,將節(jié)點(diǎn)添加到隊(duì)尾
//有效元素個(gè)數(shù)增加
public void offer(int val){
ListNode listNode=new ListNode(val);
if(isEmpty()){
first=last=listNode;
}else{
last.next=listNode;
listNode.prev=last;
last=listNode;
}
usedSize++;
}
//出隊(duì)
//判斷隊(duì)列是否為空;
//出隊(duì)頭元素,將隊(duì)頭指針向后移動(dòng)
//使用元素個(gè)數(shù)減少
public int poll(){
if(isEmpty()){
return -1;
}
int val= first.val;
first=first.next;
if(first!=null){
first.prev=null;
}
return val;
}
//獲取隊(duì)頭元素
//判斷隊(duì)列是否為空
//如果不為空,直接返回隊(duì)頭元素
public int peek(){
if(isEmpty()){
return -1;
}
return first.val;
}
//判斷是否為空
//判斷有效元素個(gè)數(shù)是否為0
public boolean isEmpty(){
return usedSize==0;
}
}4.??隊(duì)列的優(yōu)缺點(diǎn)
??優(yōu)點(diǎn):
- 順序處理:能保證順序的依次處理;
- 數(shù)據(jù)緩存:可作為數(shù)據(jù)緩存區(qū)。防止數(shù)據(jù)丟失;
- 動(dòng)態(tài)擴(kuò)展:隊(duì)列實(shí)現(xiàn)可以按需要實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)展;
??缺點(diǎn):
- 訪問受限:遵循先進(jìn)先出原則;
- 存儲(chǔ)限制:通常有長度限制,如果超過容量會(huì)有數(shù)據(jù)丟失;
- 性能問題:如果隊(duì)列過長,可能會(huì)導(dǎo)致性能下降;
到此這篇關(guān)于老生常談Java中的棧和隊(duì)列的文章就介紹到這了,更多相關(guān)java棧和隊(duì)列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)word轉(zhuǎn)pdf并在關(guān)鍵字位置插入圖片
這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)word轉(zhuǎn)pdf,并在word中關(guān)鍵字位置插入圖片,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-11-11
myBatis使用@GeneratedValue(generator?=?“...“,?strategy?=?
這篇文章主要介紹了myBatis使用@GeneratedValue(generator?=?“...“,?strategy?=?...)注解問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
基于Java語言MD5加密Base64轉(zhuǎn)換方法
這篇文章主要為大家詳細(xì)介紹了基于Java語言的MD5加密Base64轉(zhuǎn)換方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09

