建設(shè)網(wǎng)站是什么關(guān)系個(gè)人怎么注冊(cè)自己的網(wǎng)站
本文主要介紹了兩種實(shí)現(xiàn)雙端隊(duì)列的數(shù)據(jù)結(jié)構(gòu) —— 基于環(huán)形鏈表和循環(huán)數(shù)組。兩種實(shí)現(xiàn)方式的基本原理和特點(diǎn),以及詳細(xì)的Java代碼實(shí)現(xiàn)和分析。
引言
雙端隊(duì)列(Deque, Double-ended queue)是一種具有隊(duì)列和棧的性質(zhì)的數(shù)據(jù)結(jié)構(gòu)。它允許在兩端插入和刪除元素,具有較高的靈活性。雙端隊(duì)列在數(shù)據(jù)結(jié)構(gòu)和算法領(lǐng)域有廣泛的應(yīng)用,如在解決滑動(dòng)窗口最值問(wèn)題、實(shí)現(xiàn)特定需求的優(yōu)先隊(duì)列等場(chǎng)景。本文主要介紹了兩種實(shí)現(xiàn)雙端隊(duì)列的數(shù)據(jù)結(jié)構(gòu) —— 基于環(huán)形鏈表和循環(huán)數(shù)組。以下分別對(duì)這兩種實(shí)現(xiàn)方式進(jìn)行分析和講解。
1.基于環(huán)形鏈表的雙端隊(duì)列
環(huán)形鏈表是一種鏈表的擴(kuò)展, 其中鏈表的首尾相連,形成一個(gè)環(huán)。在實(shí)現(xiàn)雙端隊(duì)列時(shí),我們可以使用環(huán)形鏈表來(lái)存儲(chǔ)元素,這樣就可以方便地在表頭表尾進(jìn)行插入和刪除操作。
以下是基于環(huán)形鏈表實(shí)現(xiàn)雙端隊(duì)列的Java代碼:
/*** 基于環(huán)形鏈表的雙端隊(duì)列* @param <E> 元素類型*/
public class LinkedListDeque<E> implements Deque<E>, Iterable<E> {@Overridepublic boolean offerFirst(E e) {if (isFull()) {return false;}size++;Node<E> a = sentinel;Node<E> b = sentinel.next;Node<E> offered = new Node<>(a, e, b);a.next = offered;b.prev = offered;return true;}@Overridepublic boolean offerLast(E e) {if (isFull()) {return false;}size++;Node<E> a = sentinel.prev;Node<E> b = sentinel;Node<E> offered = new Node<>(a, e, b);a.next = offered;b.prev = offered;return true;}@Overridepublic E pollFirst() {if (isEmpty()) {return null;}Node<E> a = sentinel;Node<E> polled = sentinel.next;Node<E> b = polled.next;a.next = b;b.prev = a;size--;return polled.value;}@Overridepublic E pollLast() {if (isEmpty()) {return null;}Node<E> polled = sentinel.prev;Node<E> a = polled.prev;Node<E> b = sentinel;a.next = b;b.prev = a;size--;return polled.value;}@Overridepublic E peekFirst() {if (isEmpty()) {return null;}return sentinel.next.value;}@Overridepublic E peekLast() {if (isEmpty()) {return null;}return sentinel.prev.value;}@Overridepublic boolean isEmpty() {return size == 0;}@Overridepublic boolean isFull() {return size == capacity;}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {Node<E> p = sentinel.next;@Overridepublic boolean hasNext() {return p != sentinel;}@Overridepublic E next() {E value = p.value;p = p.next;return value;}};}static class Node<E> {Node<E> prev;E value;Node<E> next;public Node(Node<E> prev, E value, Node<E> next) {this.prev = prev;this.value = value;this.next = next;}}Node<E> sentinel = new Node<>(null, null, null);int capacity;int size;public LinkedListDeque(int capacity) {sentinel.next = sentinel;sentinel.prev = sentinel;this.capacity = capacity;}
}
優(yōu)點(diǎn):基于環(huán)形鏈表實(shí)現(xiàn)的雙端隊(duì)列具有較好的靈活性,可以實(shí)現(xiàn)任意容量大小的雙端隊(duì)列。此外,存儲(chǔ)空間會(huì)根據(jù)實(shí)際需求進(jìn)行動(dòng)態(tài)調(diào)整,避免了空間的浪費(fèi)。
缺點(diǎn):由于鏈表結(jié)構(gòu)的特性,相較于數(shù)組實(shí)現(xiàn)的雙端隊(duì)列,環(huán)形鏈表實(shí)現(xiàn)的雙端隊(duì)列空間開(kāi)銷較大。同時(shí),每次訪問(wèn)元素時(shí),都需要遍歷鏈表,導(dǎo)致時(shí)間復(fù)雜度較高。
2.基于循環(huán)數(shù)組的雙端隊(duì)列
循環(huán)數(shù)組是一種線性數(shù)據(jù)結(jié)構(gòu),它的邏輯結(jié)構(gòu)和順序表相似,但在實(shí)際存儲(chǔ)時(shí)將首尾相接,形成一個(gè)環(huán)狀結(jié)構(gòu)。在實(shí)現(xiàn)雙端隊(duì)列時(shí),可以使用循環(huán)數(shù)組來(lái)存儲(chǔ)元素。當(dāng)隊(duì)列的一端進(jìn)行插入或刪除操作時(shí),對(duì)應(yīng)的數(shù)組下標(biāo)只需加一或減一即可。
以下是基于循環(huán)數(shù)組實(shí)現(xiàn)雙端隊(duì)列的Java代碼:
/*** 基于循環(huán)數(shù)組實(shí)現(xiàn), 特點(diǎn)* <ul>* <li>tail 停下來(lái)的位置不存儲(chǔ), 會(huì)浪費(fèi)一個(gè)位置</li>* </ul>* @param <E>*/
public class ArrayDeque1<E> implements Deque<E>, Iterable<E> {/*ht0 1 2 3b a*/@Overridepublic boolean offerFirst(E e) {if (isFull()) {return false;}head = dec(head, array.length);array[head] = e;return true;}@Overridepublic boolean offerLast(E e) {if (isFull()) {return false;}array[tail] = e;tail = inc(tail, array.length);return true;}@Overridepublic E pollFirst() {if (isEmpty()) {return null;}E e = array[head];array[head] = null;head = inc(head, array.length);return e;}@Overridepublic E pollLast() {if (isEmpty()) {return null;}tail = dec(tail, array.length);E e = array[tail];array[tail] = null;return e;}@Overridepublic E peekFirst() {if (isEmpty()) {return null;}return array[head];}@Overridepublic E peekLast() {if (isEmpty()) {return null;}return array[dec(tail, array.length)];}@Overridepublic boolean isEmpty() {return head == tail;}@Overridepublic boolean isFull() {if (tail > head) {return tail - head == array.length - 1;} else if (tail < head) {return head - tail == 1;} else {return false;}}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {int p = head;@Overridepublic boolean hasNext() {return p != tail;}@Overridepublic E next() {E e = array[p];p = inc(p, array.length);return e;}};}E[] array;int head;int tail;@SuppressWarnings("unchecked")public ArrayDeque1(int capacity) {array = (E[]) new Object[capacity + 1];}static int inc(int i, int length) {if (i + 1 >= length) {return 0;}return i + 1;}static int dec(int i, int length) {if (i - 1 < 0) {return length - 1;}return i - 1;}
}
該實(shí)現(xiàn)中,為了區(qū)分隊(duì)列為空和隊(duì)列已滿的情況,我們采用了一種方法:浪費(fèi)一個(gè)數(shù)組元素。這樣,當(dāng) tail == head時(shí),隊(duì)列為空;當(dāng) (tail + 1) % array.length == head時(shí),隊(duì)列已滿。
優(yōu)點(diǎn): 基于循環(huán)數(shù)組實(shí)現(xiàn)的雙端隊(duì)列具有較好的時(shí)間復(fù)雜度,訪問(wèn)元素的時(shí)間復(fù)雜度為O(1)。此外,相比鏈表實(shí)現(xiàn)的雙端隊(duì)列,循環(huán)數(shù)組實(shí)現(xiàn)的雙端隊(duì)列空間開(kāi)銷較小,占用內(nèi)存較少。
缺點(diǎn): 循環(huán)數(shù)組實(shí)現(xiàn)的雙端隊(duì)列存在一定的空間浪費(fèi)。并且,數(shù)組的容量固定,在初始化時(shí)就要確定。如果訪問(wèn)量較大,可能導(dǎo)致數(shù)組不夠用而需要進(jìn)行擴(kuò)容操作,這將導(dǎo)致時(shí)間復(fù)雜度的降低。
結(jié)論
本文主要介紹了兩種實(shí)現(xiàn)雙端隊(duì)列的數(shù)據(jù)結(jié)構(gòu):基于環(huán)形鏈表的雙端隊(duì)列和基于循環(huán)數(shù)組的雙端隊(duì)列。根據(jù)不同的應(yīng)用場(chǎng)景和需求,可以選擇合適的數(shù)據(jù)結(jié)構(gòu)進(jìn)行實(shí)現(xiàn)。環(huán)形鏈表的雙端隊(duì)列適合容量不固定、對(duì)時(shí)間復(fù)雜度要求不高的場(chǎng)景;循環(huán)數(shù)組的雙端隊(duì)列適合對(duì)空間和時(shí)間復(fù)雜度有較高要求的場(chǎng)景。