https://labuladong.online/algo/data-structure-basic/deque-implement/
今天是學習的第 11 天,主要學習了雙端隊列(Deque)原理及實現:
雙端隊列是一種更靈活的隊列資料結構。與普通隊列相比,它在兩端都支援插入和刪除操作。
特性 | 普通隊列(Queue) | 雙端隊列(Deque) |
---|---|---|
插入位置 | 僅隊尾 | 隊頭和隊尾皆可 |
刪除位置 | 僅隊頭 | 隊頭和隊尾皆可 |
操作原則 | 先進先出(FIFO) | 靈活操作兩端 |
雙端隊列提供以下基本操作,且所有操作的時間複雜度都應為 O(1):
var MyDeque = function() {
// 從隊頭插入元素,時間複雜度 O(1)
this.addFirst = function(e) {};
// 從隊尾插入元素,時間複雜度 O(1)
this.addLast = function(e) {};
// 從隊頭刪除元素,時間複雜度 O(1)
this.removeFirst = function() {};
// 從隊尾刪除元素,時間複雜度 O(1)
this.removeLast = function() {};
// 查看隊頭元素,時間複雜度 O(1)
this.peekFirst = function() {};
// 查看隊尾元素,時間複雜度 O(1)
this.peekLast = function() {};
};
使用雙鏈表時,我們可以直接利用鏈表的特性:
雙鏈表 MyLinkedList
的實現可以參考之前的單元:苦痛之路 Day 06 - 鏈表程式碼實現。
class MyListDeque {
constructor() {
// JavaScript 中沒有提供雙鏈表,所以使用之前實現的 `MyLinkedList` 類
this.list = new MyLinkedList();
}
// 從隊頭插入元素,時間複雜度 O(1)
addFirst(e) {
this.list.addFirst(e);
}
// 從隊尾插入元素,時間複雜度 O(1)
addLast(e) {
this.list.addLast(e);
}
// 從隊頭刪除元素,時間複雜度 O(1)
removeFirst() {
return this.list.removeFirst();
}
// 從隊尾刪除元素,時間複雜度 O(1)
removeLast() {
return this.list.removeLast();
}
// 查看隊頭元素,時間複雜度 O(1)
peekFirst() {
return this.list.getFirst();
}
// 查看隊尾元素,時間複雜度 O(1)
peekLast() {
return this.list.getLast();
}
}
// 範例
const myDeque = new MyListDeque();
// head <-> 1 <-> tail
myDeque.addFirst(1);
// head <-> 2 <-> 1 <-> tail
myDeque.addFirst(2);
// head <-> 2 <-> 1 <-> 3 <-> tail
myDeque.addLast(3);
// head <-> 2 <-> 1 <-> 3 <-> 4 <-> tail
myDeque.addLast(4);
// head <-> 1 <-> 3 <-> 4 <-> tail
myDeque.removeFirst();
// head <-> 1 <-> 3 <-> tail
myDeque.removeLast();
myDeque.peekFirst(); // 1
myDeque.peekLast(); // 3
使用環形陣列時,我們需要:
start
和 end
兩個指標環形陣列 CycleArray
的實現可以參考之前的單元:苦痛之路 Day 07 - 環形陣列技巧及實現。
var MyArrayQueue = function() {
this.arr = new CycleArray();
// 從隊頭插入元素,時間複雜度 O(1)
this.addFirst = function(e) {
this.arr.addFirst(e);
};
// 從隊尾插入元素,時間複雜度 O(1)
this.addLast = function(e) {
this.arr.addLast(e);
};
// 從隊頭刪除元素,時間複雜度 O(1)
this.removeFirst = function() {
return this.arr.removeFirst();
};
// 從隊尾插入元素,時間複雜度 O(1)
this.removeLast = function() {
return this.arr.removeLast();
};
// 查看隊頭元素,時間複雜度 O(1)
this.peekFirst = function() {
return this.arr.getFirst();
};
// 查看隊尾元素,時間複雜度 O(1)
this.peekLast = function() {
return this.arr.getLast();
};
};
// 範例
const myArray = new MyArrayQueue();
// {
// arr: [1],
// count: 1,
// start: 0,
// end: 0,
// size: 1
// }
myArray.addFirst(1);
// {
// arr: [1, 2],
// count: 2,
// start: 1,
// end: 1,
// size: 2
// }
myArray.addFirst(2);
// {
// arr: [2, 1, 3, _],
// count: 3,
// start: 0,
// end: 3,
// size: 4
// }
myArray.addLast(3);
// {
// arr: [2, 1, 3, 4],
// count: 4,
// start: 0,
// end: 0,
// size: 4
// }
myArray.addLast(4);
// {
// arr: [_, 1, 3, 4],
// count: 3,
// start: 1,
// end: 0,
// size: 4
// }
myArray.removeFirst(); // 2
// {
// arr: [_, 1, 3, _],
// count: 2,
// start: 1,
// end: 3,
// size: 4
// }
myArray.removeLast(); // 4
myArray.peekFirst(); // 1
myArray.peekLast(); // 3