目錄
1、在Java中有哪些常見(jiàn)的隊(duì)列?
2、Queue 接口分析
3、Deque 接口分析
4、PriorityQueue 的實(shí)現(xiàn)原理詳解
5、使用Java數(shù)組實(shí)現(xiàn)隊(duì)列的簡(jiǎn)單示例
1、在Java中有哪些常見(jiàn)的隊(duì)列?
????????在Java中,有一些常見(jiàn)的隊(duì)列實(shí)現(xiàn)。下面是其中一些的列舉://隊(duì)列也是一種線性的數(shù)據(jù)結(jié)構(gòu)
-
ArrayList:ArrayList可以被用作隊(duì)列,通過(guò)在列表末尾添加元素,并使用
remove(0)
方法從列表的開(kāi)頭刪除元素。但是,由于在列表的開(kāi)頭刪除元素會(huì)導(dǎo)致后續(xù)元素的移動(dòng),因此對(duì)于大量的插入和刪除操作來(lái)說(shuō),ArrayList的性能可能不是最佳選擇。 -
LinkedList:LinkedList也可以用作隊(duì)列。LinkedList實(shí)現(xiàn)了
Queue
接口,可以使用offer()
方法在隊(duì)列的末尾添加元素,使用poll()
方法從隊(duì)列的開(kāi)頭刪除并返回元素。LinkedList對(duì)于插入和刪除操作具有較好的性能,因?yàn)樗褂昧酥羔榿?lái)鏈接元素,而不需要移動(dòng)其他元素。 - ArrayBlockingQueue:ArrayBlockingQueue是一個(gè)有界阻塞隊(duì)列,底層使用數(shù)組實(shí)現(xiàn)。它有一個(gè)固定的容量,并且在插入或刪除元素時(shí)可能會(huì)阻塞線程,直到滿(mǎn)足特定的條件。
- LinkedBlockingQueue:LinkedBlockingQueue是一個(gè)可選有界或無(wú)界的阻塞隊(duì)列,底層使用鏈表實(shí)現(xiàn)。它具有類(lèi)似于ArrayBlockingQueue的功能,但在內(nèi)部實(shí)現(xiàn)上略有不同。
- PriorityBlockingQueue:PriorityBlockingQueue是一個(gè)支持優(yōu)先級(jí)的無(wú)界阻塞隊(duì)列。元素按照它們的優(yōu)先級(jí)順序被插入和刪除。
- ConcurrentLinkedQueue:ConcurrentLinkedQueue是一個(gè)非阻塞無(wú)界隊(duì)列,它適用于多線程環(huán)境。它使用鏈表實(shí)現(xiàn),并且提供了高效的并發(fā)操作。
????????以上是Java中的一些常見(jiàn)隊(duì)列實(shí)現(xiàn)。具體選擇哪種隊(duì)列取決于你的需求和使用場(chǎng)景。
2、Queue 接口分析
????????Queue接口是Java集合框架中定義的一個(gè)接口,它代表了一個(gè)先進(jìn)先出(FIFO)的隊(duì)列。Queue接口繼承自Collection接口,它定義了一組方法來(lái)操作隊(duì)列中的元素。下面是Queue接口的一些主要方法和特性的詳細(xì)解釋?zhuān)?/p>
(1)添加元素:
- boolean add(E element): 將指定的元素添加到隊(duì)列的末尾,如果成功則返回true,如果隊(duì)列已滿(mǎn)則拋出異常。
- boolean offer(E element): 將指定的元素添加到隊(duì)列的末尾,如果成功則返回true,如果隊(duì)列已滿(mǎn)則返回false。
(2)移除元素:
- E remove(): 移除并返回隊(duì)列頭部的元素,如果隊(duì)列為空則拋出異常。
- E poll(): 移除并返回隊(duì)列頭部的元素,如果隊(duì)列為空則返回null。
(3)獲取頭部元素:
- E element(): 獲取隊(duì)列頭部的元素,但不移除它,如果隊(duì)列為空則拋出異常。
- E peek(): 獲取隊(duì)列頭部的元素,但不移除它,如果隊(duì)列為空則返回null。
(4)隊(duì)列大?。?/strong>
- int size(): 返回隊(duì)列中的元素個(gè)數(shù)。
- boolean isEmpty(): 判斷隊(duì)列是否為空。
????????Queue接口還有一些其他方法,如clear()用于清空隊(duì)列中的所有元素,contains(Object o)用于判斷隊(duì)列是否包含指定元素等。
????????Queue接口的常見(jiàn)實(shí)現(xiàn)類(lèi)包括LinkedList、ArrayDeque和PriorityQueue等。LinkedList實(shí)現(xiàn)了Queue接口,并且還可以作為棧使用,它是一個(gè)雙向鏈表。ArrayDeque是一個(gè)雙端隊(duì)列,它同時(shí)實(shí)現(xiàn)了Queue和Deque接口。PriorityQueue是一個(gè)基于優(yōu)先級(jí)的隊(duì)列,它允許元素按照優(yōu)先級(jí)順序被插入和刪除。
????????通過(guò)使用Queue接口,我們可以方便地進(jìn)行隊(duì)列操作,如入隊(duì)、出隊(duì)、查看隊(duì)列頭部元素等。它在處理任務(wù)調(diào)度、消息傳遞等場(chǎng)景中非常有用。
????????Java Queue接口使用示例:
????????當(dāng)使用Java中的Queue接口時(shí),我們需要選擇具體的實(shí)現(xiàn)類(lèi)來(lái)創(chuàng)建一個(gè)隊(duì)列對(duì)象。下面是一個(gè)使用Queue接口的示例,以LinkedList實(shí)現(xiàn)類(lèi)為例:
import java.util.Queue;
import java.util.LinkedList;
public class QueueExample {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)Queue對(duì)象
Queue<String> queue = new LinkedList<>();
// 添加元素到隊(duì)列
queue.add("Apple");
queue.add("Banana");
queue.add("Orange");
// 獲取隊(duì)列頭部元素
String head = queue.peek();
System.out.println("頭部元素:" + head);
// 遍歷隊(duì)列并輸出元素
System.out.println("隊(duì)列元素:");
for (String element : queue) {
System.out.println(element);
}
// 移除隊(duì)列頭部元素
String removedElement = queue.remove();
System.out.println("移除的元素:" + removedElement);
// 隊(duì)列大小
int size = queue.size();
System.out.println("隊(duì)列大小:" + size);
// 判斷隊(duì)列是否為空
boolean isEmpty = queue.isEmpty();
System.out.println("隊(duì)列是否為空:" + isEmpty);
}
}
????????在這個(gè)示例中,我們使用LinkedList作為實(shí)現(xiàn)類(lèi)創(chuàng)建了一個(gè)Queue對(duì)象。我們向隊(duì)列中添加了三個(gè)元素:"Apple","Banana"和"Orange"。然后,我們使用peek()方法獲取隊(duì)列的頭部元素,并使用for-each循環(huán)遍歷隊(duì)列并輸出每個(gè)元素。
????????接下來(lái),我們使用remove()方法移除隊(duì)列的頭部元素,并使用size()方法獲取隊(duì)列的大小。最后,我們使用isEmpty()方法判斷隊(duì)列是否為空。
3、Deque 接口分析
????????Deque接口是Java集合框架中定義的一個(gè)接口,它代表了一個(gè)雙端隊(duì)列(Double Ended Queue)。Deque是"雙端隊(duì)列"的縮寫(xiě)。Deque接口繼承自Queue接口,并在其基礎(chǔ)上提供了在隊(duì)列兩端進(jìn)行添加、刪除和檢索元素的操作。Deque可以在隊(duì)列的頭部和尾部同時(shí)進(jìn)行元素的插入和刪除,因此可以作為隊(duì)列、棧或雙向隊(duì)列使用。
????????Deque接口定義了以下主要方法和特性:
(1)添加元素:
- void addFirst(E element): 將指定元素添加到雙端隊(duì)列的頭部。
- void addLast(E element): 將指定元素添加到雙端隊(duì)列的尾部。
- boolean offerFirst(E element): 將指定元素添加到雙端隊(duì)列的頭部,如果成功則返回true,如果隊(duì)列已滿(mǎn)則返回false。
- boolean offerLast(E element): 將指定元素添加到雙端隊(duì)列的尾部,如果成功則返回true,如果隊(duì)列已滿(mǎn)則返回false。
(2)移除元素:
- E removeFirst(): 移除并返回雙端隊(duì)列的頭部元素,如果隊(duì)列為空則拋出異常。
- E removeLast(): 移除并返回雙端隊(duì)列的尾部元素,如果隊(duì)列為空則拋出異常。
- E pollFirst(): 移除并返回雙端隊(duì)列的頭部元素,如果隊(duì)列為空則返回null。
- E pollLast(): 移除并返回雙端隊(duì)列的尾部元素,如果隊(duì)列為空則返回null。
(3)獲取頭部和尾部元素:
- E getFirst(): 獲取雙端隊(duì)列的頭部元素,但不移除它,如果隊(duì)列為空則拋出異常。
- E getLast(): 獲取雙端隊(duì)列的尾部元素,但不移除它,如果隊(duì)列為空則拋出異常。
- E peekFirst(): 獲取雙端隊(duì)列的頭部元素,但不移除它,如果隊(duì)列為空則返回null。
- E peekLast(): 獲取雙端隊(duì)列的尾部元素,但不移除它,如果隊(duì)列為空則返回null。
????????Deque接口還提供了一些其他方法,如size()用于返回雙端隊(duì)列中的元素個(gè)數(shù),isEmpty()用于判斷雙端隊(duì)列是否為空,clear()用于清空雙端隊(duì)列中的所有元素等。
????????Deque接口的常見(jiàn)實(shí)現(xiàn)類(lèi)包括ArrayDeque和LinkedList。ArrayDeque是一個(gè)基于數(shù)組實(shí)現(xiàn)的雙端隊(duì)列,支持高效的隨機(jī)訪問(wèn)和動(dòng)態(tài)擴(kuò)展。LinkedList是一個(gè)基于鏈表實(shí)現(xiàn)的雙端隊(duì)列,支持高效的插入和刪除操作。
????????通過(guò)使用Deque接口,我們可以方便地進(jìn)行雙端隊(duì)列操作,如在隊(duì)列的頭部和尾部插入和刪除元素,獲取頭部和尾部元素,以及判斷隊(duì)列是否為空。Deque在許多場(chǎng)景下都很有用,比如實(shí)現(xiàn)LRU緩存、實(shí)現(xiàn)任務(wù)調(diào)度等。
????????另外,需要注意的是,Deque接口還可以用作棧(LIFO)的數(shù)據(jù)結(jié)構(gòu)。通過(guò)在隊(duì)列頭部執(zhí)行插入和刪除操作,可以實(shí)現(xiàn)棧的功能。常見(jiàn)的棧操作可以使用Deque接口中的以下方法來(lái)實(shí)現(xiàn):
- void push(E element): 將元素推入棧頂,等同于addFirst(E element)。
- E pop(): 彈出并返回棧頂元素,等同于removeFirst()。
- E peek(): 獲取棧頂元素,等同于peekFirst()。
????????所以,Deque接口是一個(gè)非常有用的接口,提供了雙端隊(duì)列的功能,既可以在隊(duì)列的頭部進(jìn)行操作,也可以在尾部進(jìn)行操作。它是Queue接口的擴(kuò)展,可以方便地實(shí)現(xiàn)隊(duì)列、棧和雙向隊(duì)列的功能,并提供了豐富的方法來(lái)操作和訪問(wèn)隊(duì)列中的元素。
????????Java Deque 接口使用示例
????????當(dāng)使用Java中的Deque接口時(shí),我們同樣需要選擇具體的實(shí)現(xiàn)類(lèi)來(lái)創(chuàng)建一個(gè)雙端隊(duì)列對(duì)象。下面是一個(gè)使用Deque接口的示例,以ArrayDeque實(shí)現(xiàn)類(lèi)為例:
import java.util.Deque;
import java.util.ArrayDeque;
public class DequeExample {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)Deque對(duì)象
Deque<String> deque = new ArrayDeque<>();
// 添加元素到雙端隊(duì)列
deque.addFirst("Apple");
deque.addLast("Banana");
deque.addLast("Orange");
// 獲取雙端隊(duì)列頭部和尾部元素
String first = deque.getFirst();
String last = deque.getLast();
System.out.println("頭部元素:" + first);
System.out.println("尾部元素:" + last);
// 遍歷雙端隊(duì)列并輸出元素
System.out.println("雙端隊(duì)列元素(從頭到尾):");
for (String element : deque) {
System.out.println(element);
}
// 移除雙端隊(duì)列頭部和尾部元素
String removedFirst = deque.removeFirst();
String removedLast = deque.removeLast();
System.out.println("移除的頭部元素:" + removedFirst);
System.out.println("移除的尾部元素:" + removedLast);
// 雙端隊(duì)列大小
int size = deque.size();
System.out.println("雙端隊(duì)列大?。? + size);
// 判斷雙端隊(duì)列是否為空
boolean isEmpty = deque.isEmpty();
System.out.println("雙端隊(duì)列是否為空:" + isEmpty);
}
}
????????在這個(gè)示例中,我們使用ArrayDeque作為實(shí)現(xiàn)類(lèi)創(chuàng)建了一個(gè)Deque對(duì)象。我們向雙端隊(duì)列中添加了三個(gè)元素:"Apple"、"Banana"和"Orange"。然后,我們使用getFirst()和getLast()方法分別獲取雙端隊(duì)列的頭部和尾部元素,并使用for-each循環(huán)遍歷雙端隊(duì)列并輸出每個(gè)元素。
????????接下來(lái),我們使用removeFirst()和removeLast()方法移除雙端隊(duì)列的頭部和尾部元素,并使用size()方法獲取雙端隊(duì)列的大小。最后,我們使用isEmpty()方法判斷雙端隊(duì)列是否為空。
4、PriorityQueue 的實(shí)現(xiàn)原理詳解
????????PriorityQueue的實(shí)現(xiàn)原理是基于二叉堆(Binary Heap),它是一種特殊的完全二叉樹(shù)結(jié)構(gòu),具有以下性質(zhì):
- 最小堆性質(zhì):在最小堆中,每個(gè)節(jié)點(diǎn)的值都小于或等于其子節(jié)點(diǎn)的值。也就是說(shuō),堆的根節(jié)點(diǎn)是最小的元素。
????????PriorityQueue使用一個(gè)數(shù)組來(lái)存儲(chǔ)元素,并通過(guò)二叉堆的形式來(lái)組織這些元素。數(shù)組中的元素按照特定的順序排列,滿(mǎn)足最小堆的性質(zhì)。在數(shù)組中,根節(jié)點(diǎn)位于索引0處,而對(duì)于任意位置i的節(jié)點(diǎn),它的左子節(jié)點(diǎn)位于索引2i+1處,右子節(jié)點(diǎn)位于索引2i+2處。
????????當(dāng)元素被添加到PriorityQueue時(shí),它會(huì)被放置在數(shù)組的末尾,并按照以下步驟進(jìn)行調(diào)整,以維護(hù)最小堆的性質(zhì):
- 上濾(Up-Heap)操作:新插入的元素會(huì)與其父節(jié)點(diǎn)進(jìn)行比較。如果新插入的元素的優(yōu)先級(jí)比父節(jié)點(diǎn)的優(yōu)先級(jí)低(或者更大),則它會(huì)與父節(jié)點(diǎn)進(jìn)行交換,直到滿(mǎn)足最小堆的性質(zhì)。
????????當(dāng)從PriorityQueue中刪除元素時(shí),隊(duì)列頭部的元素被移除,并將數(shù)組的最后一個(gè)元素移動(dòng)到頭部位置。然后,這個(gè)元素會(huì)與其子節(jié)點(diǎn)進(jìn)行比較,以保持最小堆的性質(zhì)。
- 下濾(Down-Heap)操作:被移動(dòng)到頭部位置的元素會(huì)與其子節(jié)點(diǎn)進(jìn)行比較。如果它的優(yōu)先級(jí)比其中一個(gè)或兩個(gè)子節(jié)點(diǎn)的優(yōu)先級(jí)高(或者更?。?,則它會(huì)與較小的子節(jié)點(diǎn)進(jìn)行交換。這個(gè)過(guò)程會(huì)遞歸地向下進(jìn)行,直到滿(mǎn)足最小堆的性質(zhì)。
????????通過(guò)上述的上濾和下濾操作,PriorityQueue可以保持最小堆的性質(zhì),使得具有最高優(yōu)先級(jí)的元素總是位于隊(duì)列的頭部。
????????PriorityQueue的插入和刪除操作的時(shí)間復(fù)雜度都是O(logN),其中N是隊(duì)列中的元素個(gè)數(shù)。這是因?yàn)檫@些操作涉及到堆的調(diào)整,需要按照樹(shù)的高度來(lái)進(jìn)行操作。同時(shí),PriorityQueue還支持高效的查找具有最高優(yōu)先級(jí)的元素,時(shí)間復(fù)雜度為O(1)。
????????需要注意的是,PriorityQueue允許元素具有相同的優(yōu)先級(jí),但它們的順序不一定是確定的。在這種情況下,PriorityQueue的行為是不保證的,具有相同優(yōu)先級(jí)的元素可能會(huì)以任意順序被取出。
????????優(yōu)先隊(duì)列(PriorityQueue)的使用示例:
public static void main(String[] args) {
//默認(rèn)采用的是最小堆實(shí)現(xiàn)的
PriorityQueue<Integer> queue = new PriorityQueue<Integer>(10, new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
return a - b; //if a>b 則交換,so這是遞增序列
}
});
queue.offer(13);
queue.offer(9);
int len = queue.size();
for (int i = 0; i < len; i++) {
System.out.println(queue.poll());
}
//輸出 9 13
//默認(rèn)采用的是最小堆實(shí)現(xiàn)的
PriorityQueue<Integer> queue2 = new PriorityQueue<>(10);
queue2.offer(11);
queue2.offer(9);
len = queue2.size();
for (int i = 0; i < len; i++) {
System.out.println(queue2.poll());
}
//輸出 9, 11
}
5、使用Java數(shù)組實(shí)現(xiàn)隊(duì)列的簡(jiǎn)單示例
????????下面是使用Java數(shù)組實(shí)現(xiàn)隊(duì)列的簡(jiǎn)單示例代碼:
public class ArrayQueue {
private int[] queue; // 內(nèi)部數(shù)組
private int front; // 隊(duì)列頭部指針
private int rear; // 隊(duì)列尾部指針
private int size; // 隊(duì)列當(dāng)前元素個(gè)數(shù)
private int capacity; // 隊(duì)列容量
public ArrayQueue(int capacity) {
this.capacity = capacity;
queue = new int[capacity];
front = 0;
rear = -1;
size = 0;
}
public boolean isEmpty() {
return size == 0;
}
public boolean isFull() {
return size == capacity;
}
public int size() {
return size;
}
public void enqueue(int item) {
if (isFull()) {
System.out.println("Queue is full. Cannot enqueue.");
return;
}
rear = (rear + 1) % capacity; // 循環(huán)隊(duì)列,計(jì)算新的尾部位置
queue[rear] = item;
size++;
System.out.println("Enqueued: " + item);
}
public int dequeue() {
if (isEmpty()) {
System.out.println("Queue is empty. Cannot dequeue.");
return -1;
}
int item = queue[front];
front = (front + 1) % capacity; // 循環(huán)隊(duì)列,計(jì)算新的頭部位置
size--;
System.out.println("Dequeued: " + item);
return item;
}
public int peek() {
if (isEmpty()) {
System.out.println("Queue is empty.");
return -1;
}
return queue[front];
}
public void display() {
if (isEmpty()) {
System.out.println("Queue is empty.");
return;
}
System.out.print("Queue: ");
int index = front;
for (int i = 0; i < size; i++) {
System.out.print(queue[index] + " ");
index = (index + 1) % capacity; // 循環(huán)遍歷隊(duì)列
}
System.out.println();
}
public static void main(String[] args) {
ArrayQueue queue = new ArrayQueue(5);
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
queue.display(); // Queue: 10 20 30
queue.dequeue();
queue.display(); // Queue: 20 30
queue.enqueue(40);
queue.enqueue(50);
queue.display(); // Queue: 20 30 40 50
queue.dequeue();
queue.dequeue();
queue.display(); // Queue: 40 50
}
}
????????以上示例演示了使用Java數(shù)組實(shí)現(xiàn)的簡(jiǎn)單隊(duì)列(循環(huán)隊(duì)列)。通過(guò)enqueue()方法將元素入隊(duì),dequeue()方法將元素出隊(duì),peek()方法返回隊(duì)列頭部元素,size()方法返回隊(duì)列當(dāng)前元素個(gè)數(shù),isEmpty()方法和isFull()方法檢查隊(duì)列是否為空或已滿(mǎn)。display()方法用于打印隊(duì)列中的元素。
????????上述循環(huán)隊(duì)列實(shí)現(xiàn)的具體步驟總結(jié)如下:
(1)入隊(duì)操作(enqueue):
- 首先,檢查隊(duì)列是否已滿(mǎn)(isFull()方法)。如果已滿(mǎn),則無(wú)法入隊(duì),并輸出相應(yīng)的提示信息。
- 否則,計(jì)算新的尾部位置(rear = (rear + 1) % capacity),并將新元素存儲(chǔ)到該位置。
- 增加隊(duì)列的元素個(gè)數(shù)(size++)。
- 輸出入隊(duì)的元素信息。
(2)出隊(duì)操作(dequeue):
- 首先,檢查隊(duì)列是否為空(isEmpty()方法)。如果為空,則無(wú)法出隊(duì),并輸出相應(yīng)的提示信息。
- 否則,獲取頭部元素(queue[front])并保存到臨時(shí)變量中。
- 計(jì)算新的頭部位置(front = (front + 1) % capacity)。
- 減少隊(duì)列的元素個(gè)數(shù)(size--)。
- 輸出出隊(duì)的元素信息,并返回該元素的值。
(3)查看頭部元素(peek):
- 首先,檢查隊(duì)列是否為空(isEmpty()方法)。如果為空,則輸出相應(yīng)的提示信息并返回特定的值(如-1)。
- 否則,返回頭部元素(queue[front])的值。
(4)判斷隊(duì)列是否為空(isEmpty):
- 根據(jù)隊(duì)列的元素個(gè)數(shù)(size)是否為0來(lái)判斷隊(duì)列是否為空。
(5)判斷隊(duì)列是否已滿(mǎn)(isFull):
- 根據(jù)隊(duì)列的元素個(gè)數(shù)(size)是否等于隊(duì)列的容量(capacity)來(lái)判斷隊(duì)列是否已滿(mǎn)。
(6)遍歷打印隊(duì)列中的元素(display):文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-609193.html
- 首先,檢查隊(duì)列是否為空(isEmpty()方法)。如果為空,則輸出相應(yīng)的提示信息。
- 否則,從頭部位置(front)開(kāi)始循環(huán)遍歷隊(duì)列中的元素,依次輸出每個(gè)元素。
- 注意使用循環(huán)變量(index)進(jìn)行索引,并通過(guò)取余運(yùn)算實(shí)現(xiàn)循環(huán)遍歷。
????????這樣,通過(guò)以上實(shí)現(xiàn),我們可以使用Java數(shù)組來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的隊(duì)列,并進(jìn)行入隊(duì)、出隊(duì)、查看頭部元素以及遍歷打印等操作。這種基于數(shù)組的實(shí)現(xiàn)方式可以滿(mǎn)足隊(duì)列的基本需求,并且具有較好的性能。但需要注意的是,由于數(shù)組的容量是固定的,當(dāng)隊(duì)列已滿(mǎn)時(shí),無(wú)法再添加新的元素,除非進(jìn)行元素的出隊(duì)操作。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-609193.html
到了這里,關(guān)于Java 數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Queue)詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!