準備學習《學習JavaScript資料結構與演算法》,自己也開始做一寫筆記來記錄總結,本文也是僅針對實現方面的總結。
如果出現錯誤,請在評論中指出,我也好自己糾正自己的錯誤
author: thomaszhou
棧的實現
棧,其實就是一個陣列,但是這是個非常特殊的陣列,因為棧有個特性:先進後出,什麼意思呢?看著下面的圖來講解。
原諒我是個靈魂畫手
-
棧只有一個開口,這個開口,是進口,也是出口
- 我們從這個口新增資料,也從這個口取出資料
-
棧的原則:先進後出
- 我們依次新增1,2,3進入棧中,那我們取出的第一個值是3,第二個取出的值是2,第三個是1。那如果在取出2的時候,又新增一個數呢?大家可以模擬一下
-
定義棧類和宣告的方法
function Stack() { //定義棧 的類
var items = [];
this.push = function(elem) {//新增元素
return items.push(elem);
};
this.pop = function() {//彈出元素
return items.pop();
};
this.print = function() { //輸出
console.log(items.toString());
};
this.size = function() {//輸出棧的長度
return items.length;
};
this.clear = function() {//將棧置為空
return items = [];
};
this.peek = function() {//顯示頂層元素
return items[items.length-1]
};
this.isEmpty = function() { // 判斷棧是否為空
return items.length === 0;
};
}
複製程式碼
棧的測試函式
(function demo1() {
let stack1 = new Stack(); //建立棧
stack1.push(1);
stack1.push(2);
stack1.push(3);
stack1.push(4);
stack1.print();
console.log(stack1.pop());//4
console.log(stack1.peek());// 3
console.log(stack1.isEmpty());// false
stack1.clear();
console.log(stack1.isEmpty());// true
})();
複製程式碼
- 棧的例子:十進位制轉換為任意進位制
function divideBy2(elem, base) {
var str = '',
temp = 0,
arr = new Stack(),//建立棧
baseStr = '0123456789ABCDEF';
while (elem !== 0) {
arr.push(Math.floor(elem % base));//容易漏掉Math.floor()就會造成結果為undefine;
elem = Math.floor(elem / base);
//
//console.log(elem); 測試debug
}
while (!arr.isempty()) {
console.log(arr);
str += baseStr[arr.pop()]; // 字串也是陣列,所有要用baseStr[]。而不能用baseStr()
}
return str;
}
console.log(divideBy2(7, 2));
複製程式碼
佇列的實現
(1) 普通佇列
- 佇列和棧的不同就在於:
- 1、棧是先進後出,那就是push和pop方法
- 2、佇列是先進先出,那就是push和shift方法
- 我們看啊,從右邊進去,依次新增1,2,3,4,取出的第一個值是啥?是1,第二個,第三個第四個就是2,3,4.也就是說,我們新增一定是從右邊進去,取出一定是從左邊出去,也就是上面說的先進先出,先進去的,就先出來
function Queue() {
let items = [];
this.enqueue = function(ele) {
items.push(ele);
};
this.dequeue = function() {
return items.shift();
};
this.front = function() {
return items[0];
};
// 下面方法 同 棧
this.isEmpty = function() {
return items.length === 0;
};
this.clear = function() {
items = [];
};
this.size = function() {
return items.length;
};
this.print = function() {
console.log(items.toString());
}
}
複製程式碼
普通佇列的測試函式:
(function queueDemo() {
var queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.print(); //1,2,3
console.log(queue.dequeue()); //1
console.log(queue.isEmpty()); //false
console.log(queue.size()); //2
console.log(queue.front()); //2
queue.clear();
console.log(queue.size()); // 0
})();
複製程式碼
(2) 優先佇列
優先佇列的核心在於設定優先順序,佇列的每個資料不是單一值,而是一個值和一個優先順序id
- 1、 採用建構函式,構造一個含有element和priority的例項
- 2、 每次新增例項到佇列中,按照優先順序的先後插入到佇列中(splice方法)
// 優先佇列
function PriorityQueue() {
let items = [];
function QueueElement(element, priority) {
this.element = element;
this.priority = priority;
}
this.enqueue = function(element, priority) {
let ele = new QueueElement(element, priority);
if (this.isEmpty() === true) { // 佇列為空,直接push
items.push(ele);
}else {
// 佇列不為空,element的優先順序priority小的在前面
for (let i = 0; i < items.length; i++) {
if (ele.priority < items[i].priority) {
items.splice(i, 0, ele);
}else {
// element的優先順序最低的情況-直接push到最後
items.push(ele);
}
break;
}
}
};
this.print = function() {
for (let i = 0; i < items.length; i++) {
console.log(`ele: ${items[i].element},prio: ${items[i].priority}`);
}
};
// 其他的方法和普通佇列相同
this.dequeue = function() {
return items.shift();
};
this.front = function() {
return items[0];
};
this.isEmpty = function() {
return items.length === 0;
};
this.clear = function() {
items = [];
};
this.size = function() {
return items.length;
};
}
複製程式碼
優先佇列測試函式:
(function priQueueDemo() {
var queue = new PriorityQueue();
queue.enqueue(1, 4);
queue.enqueue(2, 7);
queue.enqueue(3, 1);
queue.print();
// ele: 3,prio: 1
// ele: 1,prio: 4
// ele: 2,prio: 7
console.log(queue.dequeue());//QueueElement {element: 3, priority: 1}
console.log(queue.isEmpty());//false
console.log(queue.size());//2
console.log(queue.front());//QueueElement {element: 1, priority: 4}
queue.clear();
console.log(queue.size());// 0
})();
複製程式碼
(3)迴圈佇列
迴圈佇列和普通佇列的區別:普通佇列和迴圈佇列都是後面進一個,前面進一個.不同點就在於,迴圈佇列是要將彈出的元素再返回到尾部再新增進去
核心程式碼就是queue.enqueue(queue.dequeue())
迴圈佇列的應用-擊鼓傳花
擊鼓傳花的遊戲都玩過,就是一堆人圍一個圈,然後傳遞花,輪一圈,誰拿到花就淘汰誰(我們的例子是通過設定num來表示一輪傳遞幾個人,算是一個規律性的擊鼓傳花,如果想實現真正的擊鼓傳花,那麼就設定num為random,然後設定一個範圍,就可以了,num = Math.floor(num * Math.random())
)
- 所以也只是一個虛擬的遊戲
function hotPotato (nameList, num) {
let queue = new Queue(),
len = nameList.length;
for (let i = 0; i < len; i++) {
queue.enqueue(nameList[i]);
}
while (queue.size() > 1) {// 佇列最後剩下一個
for (let i = 0; i < num; i++) {
queue.enqueue(queue.dequeue());// 迴圈佇列的核心
}
console.log(`${queue.dequeue()}被淘汰`);
}
console.log(`${queue.dequeue()}勝利`);//佇列的最後一個值
}
let arr = ['thomas1', 'thomas2', 'thomas3', 'thomas4', 'thomas5'];
hotPotato(arr, 2);
//thomas3被淘汰
//thomas1被淘汰
//thomas5被淘汰
//thomas2被淘汰
//thomas4勝利
複製程式碼