【從蛋殼到滿天飛】JS 數據結構解析和算法實現,所有文章大概的內容以下: Arrays(數組)、Stacks(棧)、Queues(隊列)、LinkedList(鏈表)、Recursion(遞歸思想)、BinarySearchTree(二分搜索樹)、Set(集合)、Map(映射)、Heap(堆)、PriorityQueue(優先隊列)、SegmentTree(線段樹)、Trie(字典樹)、UnionFind(並查集)、AVLTree(AVL 平衡樹)、RedBlackTree(紅黑平衡樹)、HashTable(哈希表)html
源代碼有三個:ES6(單個單個的 class 類型的 js 文件) | JS + HTML(一個 js 配合一個 html)| JAVA (一個一個的工程)node
所有源代碼已上傳 github,點擊我吧,光看文章可以掌握兩成,動手敲代碼、動腦思考、畫圖才能夠掌握八成。git
本文章適合 對數據結構想了解而且感興趣的人羣,文章風格一如既往如此,就以爲手機上看起來比較方便,這樣顯得比較有條理,整理這些筆記加源碼,時間跨度也算將近半年時間了,但願對想學習數據結構的人或者正在學習數據結構的人羣有幫助。github
添加元素的狀況面試
在紅黑樹中的三節點中添加元素的第一種狀況算法
下圖中節點 37 和節點 42 已經造成了一個三節點,數組
由於所謂紅色節點的意思就是它和它的父親是融合在一塊兒的,數據結構
若是這個時候再添加一個元素 66,新添加的節點默認爲紅色,dom
那麼按照二分搜索樹中的性質,這個元素會被添加爲根節點 44 的右孩子,ide
此時就會對應二三樹中臨時的四節點,在紅黑樹的表示就是,
根節點是黑色的,左右孩子節點都是紅色的,
所謂紅色節點的意思就是它和它的父親是融合在一塊兒的。
// 中括號爲黑色節點,大括號爲紅色節點
// [42]
// /
// {37}
// 添加元素 66
// [42]
// / \
// {37} {66}
複製代碼
顏色翻轉
在二三樹中這個臨時的四節點以後會被分裂成三個二節點,
對應紅黑樹中的操做是將根節點 42 下面兩個節點 37 和 66 都染成黑色,
這樣就表示了在二三樹中三個二節點組成了一棵子樹,
臨時的四節點分裂以後,新的子樹的根節點須要向上進行融合操做,
因此在紅黑樹中的操做是,這個根節點 42 要變成紅色,
由於所謂紅色節點的意思就是它和它的父親是融合在一塊兒的,
這個過程就讓根節點的顏色與左右子樹的顏色進行了一個翻轉操做,
顏色翻轉的英文就是 flipColors,這是在紅黑樹中添加一個新元素的輔助過程,
實際上也是等價的在二三樹中的三節點中添加了一個新元素所對應的一個輔助過程。
// 中括號爲黑色節點,大括號爲紅色節點
// 添加元素 66
// [42]
// / \
// {37} {66}
// 顏色翻轉
// {42}
// / \
// [37] [66]
複製代碼
在紅黑樹中的三節點中添加元素的另一種狀況
// 中括號爲黑色節點,大括號爲紅色節點
// [42]
// /
// {37}
// 添加元素 12
// [42]
// /
// {37}
// /
// {23}
複製代碼
右旋轉
// 中括號爲黑色節點,大括號爲紅色節點
// 小括號只是參與演示,並不真實存在
// 原來是這樣的
// [42] node
// / \
// x {37} (T2)
// / \
// {23} (T1)
// 進行右旋轉後
// {37} x
// / \
// {23} {42} node
// / \
// (T1) (T2)
// node.left = T1
// x.right = node;
// x.color = node.color;
// node.color = RED;
// 顏色翻轉後
// {37} x
// / \
// [23] [42] node
// / \
// (T1) (T2)
// x.color = RED;
// x.left.color = BLACK;
// x.right.color = BLACK;
複製代碼
MyRedBlackTree
// 自定義紅黑樹節點 RedBalckTreeNode
class MyRedBalckTreeNode {
constructor(key = null, value = null, left = null, right = null) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
this.color = MyRedBlackTree.RED; // MyRedBlackTree.BLACK;
}
// @Override toString 2018-11-25-jwl
toString() {
return (
this.key.toString() +
'--->' +
this.value.toString() +
'--->' +
(this.color ? '紅色節點' : '綠色節點')
);
}
}
// 自定義紅黑樹 RedBlackTree
class MyRedBlackTree {
constructor() {
MyRedBlackTree.RED = true;
MyRedBlackTree.BLACK = false;
this.root = null;
this.size = 0;
}
// 判斷節點node的顏色
isRed(node) {
// 定義:空節點顏色爲黑色
if (!node) return MyRedBlackTree.BLACK;
return node.color;
}
// node x
// / \ 左旋轉 / \
// T1 x ---------> node T3
// / \ / \
// T2 T3 T1 T2
leftRotate(node) {
const x = node.right;
// 左旋轉過程
node.right = x.left;
x.left = node;
// 染色過程
x.color = node.color;
node.color = MyRedBlackTree.RED;
// 返回這個 x
return x;
}
// 顏色翻轉 當前節點變紅 左右孩子變黑
// 表示當前節點須要繼續向上進行融合
flipColors(node) {
node.color = MyRedBlackTree.RED;
node.left.color = MyRedBlackTree.BLACK;
node.right.color = MyRedBlackTree.BLACK;
}
// node x
// / \ 右旋轉 / \
// x T2 -------> y node
// / \ / \
// y T1 T1 T2
rightRotate(node) {
const x = node.left;
// 右翻轉過程
node.left = x.right;
x.right = node;
// 染色過程
x.color = node.color;
node.color = MyRedBlackTree.RED;
// 返回這個 x
return x;
}
// 比較的功能
compare(keyA, keyB) {
if (keyA === null || keyB === null)
throw new Error("key is error. key can't compare.");
if (keyA > keyB) return 1;
else if (keyA < keyB) return -1;
else return 0;
}
// 根據key獲取節點 -
getNode(node, key) {
// 先解決最基本的問題
if (node === null) return null;
// 開始將複雜的問題 逐漸縮小規模
// 從而求出小問題的解,最後構建出原問題的解
switch (this.compare(node.key, key)) {
case 1: // 向左找
return this.getNode(node.left, key);
break;
case -1: // 向右找
return this.getNode(node.right, key);
break;
case 0: // 找到了
return node;
break;
default:
throw new Error(
'compare result is error. compare result : 0、 一、 -1 .'
);
break;
}
}
// 添加操做 +
add(key, value) {
this.root = this.recursiveAdd(this.root, key, value);
this.root.color = MyRedBlackTree.BLACK;
}
// 添加操做 遞歸算法 -
recursiveAdd(node, key, value) {
// 解決最簡單的問題
if (node === null) {
this.size++;
return new MyRedBalckTreeNode(key, value);
}
// 將複雜的問題規模逐漸變小,
// 從而求出小問題的解,從而構建出原問題的答案
if (this.compare(node.key, key) > 0)
node.left = this.recursiveAdd(node.left, key, value);
else if (this.compare(node.key, key) < 0)
node.right = this.recursiveAdd(node.right, key, value);
else node.value = value;
return node;
}
// 刪除操做 返回被刪除的元素 +
remove(key) {
let node = this.getNode(this.root, key);
if (node === null) return null;
this.root = this.recursiveRemove(this.root, key);
return node.value;
}
// 刪除操做 遞歸算法 +
recursiveRemove(node, key) {
// 解決最基本的問題
if (node === null) return null;
if (this.compare(node.key, key) > 0) {
node.left = this.recursiveRemove(node.left, key);
return node;
} else if (this.compare(node.key, key) < 0) {
node.right = this.recursiveRemove(node.right, key);
return node;
} else {
// 當前節點的key 與 待刪除的key的那個節點相同
// 有三種狀況
// 1. 當前節點沒有左子樹,那麼只有讓當前節點的右子樹直接覆蓋當前節點,就表示當前節點被刪除了
// 2. 當前節點沒有右子樹,那麼只有讓當前節點的左子樹直接覆蓋當前節點,就表示當前節點被刪除了
// 3. 當前節點左右子樹都有, 那麼又分兩種狀況,使用前驅刪除法或者後繼刪除法
// 1. 前驅刪除法:使用當前節點的左子樹上最大的那個節點覆蓋當前節點
// 2. 後繼刪除法:使用當前節點的右子樹上最小的那個節點覆蓋當前節點
if (node.left === null) {
let rightNode = node.right;
node.right = null;
this.size--;
return rightNode;
} else if (node.right === null) {
let leftNode = node.left;
node.left = null;
this.size--;
return leftNode;
} else {
let predecessor = this.maximum(node.left);
node.left = this.removeMax(node.left);
this.size++;
// 開始嫁接 當前節點的左右子樹
predecessor.left = node.left;
predecessor.right = node.right;
// 將當前節點從根節點剔除
node = node.left = node.right = null;
this.size--;
// 返回嫁接後的新節點
return predecessor;
}
}
}
// 刪除操做的兩個輔助函數
// 獲取最大值、刪除最大值
// 之前驅的方式 來輔助刪除操做的函數
// 獲取最大值
maximum(node) {
// 不再能往右了,說明當前節點已是最大的了
if (node.right === null) return node;
// 將複雜的問題漸漸減少規模,從而求出小問題的解,最後用小問題的解構建出原問題的答案
return this.maximum(node.right);
}
// 刪除最大值
removeMax(node) {
// 解決最基本的問題
if (node.right === null) {
let leftNode = node.left;
node.left = null;
this.size--;
return leftNode;
}
// 開始化歸
node.right = this.removeMax(node.right);
return node;
}
// 查詢操做 返回查詢到的元素 +
get(key) {
let node = this.getNode(this.root, key);
if (node === null) return null;
return node.value;
}
// 修改操做 +
set(key, value) {
let node = this.getNode(this.root, key);
if (node === null) throw new Error(key + " doesn't exist.");
node.value = value;
}
// 返回是否包含該key的元素的判斷值 +
contains(key) {
return this.getNode(this.root, key) !== null;
}
// 返回映射中實際的元素個數 +
getSize() {
return this.size;
}
// 返回映射中是否爲空的判斷值 +
isEmpty() {
return this.size === 0;
}
// @Override toString() 2018-11-05-jwl
toString() {
let mapInfo = `MyBinarySearchTreeMap: size = ${this.size}, data = [ `;
document.body.innerHTML += `MyBinarySearchTreeMap: size = ${ this.size }, data = [ <br/><br/>`;
// 以非遞歸的前序遍歷 輸出字符串
let stack = new MyLinkedListStack();
stack.push(this.root);
if (this.root === null) stack.pop();
while (!stack.isEmpty()) {
let node = stack.pop();
if (node.left !== null) stack.push(node.left);
if (node.right !== null) stack.push(node.right);
if (node.left === null && node.right === null) {
mapInfo += ` ${node.toString()} \r\n`;
document.body.innerHTML += ` ${node.toString()} <br/><br/>`;
} else {
mapInfo += ` ${node.toString()}, \r\n`;
document.body.innerHTML += ` ${node.toString()}, <br/><br/>`;
}
}
mapInfo += ` ] \r\n`;
document.body.innerHTML += ` ] <br/><br/>`;
return mapInfo;
}
}
複製代碼
在紅黑樹中添加新節點等價於在二三樹的一個二或三節點上融合一個新的元素
在二節點上進行融合操做,
若是新添加的這個節點比最後找到的葉子節點的元素小,
那麼對應在紅黑樹中的操做就是直接添加爲當前節點的左孩子便可;
若是新添加的這個節點比最後找到的葉子節點的元素大,
那麼對應在紅黑樹中的操做是 首先直接添加爲當前節點的右孩子,
而後再進行左旋轉操做,讓新添加的節點做爲根節點,
而原來的根節點做爲新添加的節點的左孩子節點便可;
左旋轉操做須要將新的根節點與原來的根節點的顏色對調,
而後將原來的根節點染色爲紅色,最後,
左旋轉的過程當中並不會去維護紅黑樹的性質,
左旋轉的做用只是讓這兩個節點對應成二三樹中的三節點。
在三節點上進行融合操做,
若是新添加的這個節點比根節點要大,
那麼對應在紅黑樹中的操做就是直接添加爲根節點的右孩子,
以後進行一下顏色的翻轉操做便可;
若是新添加的這個節點比根節點要小而且比根節點的左孩子要小,
那麼對應在紅黑樹中的操做就是先直接添加爲根節點的左孩子的左孩子,
而後進行一下右旋轉,
旋轉右旋轉操做須要將新的根節點與原來的根節點的顏色對調,
而後將原來的根節點染色爲紅色,
也是同樣,旋轉操做不會去維護紅黑樹的性質,
右旋轉的做用只是讓這三個節點對應成二三樹中的臨時四節點,
以後進行一下顏色的翻轉操做便可;
若是新添加的這個節點比根節點要小而且比根節點的左孩子要大,
那麼對應在紅黑樹中的操做就是先直接添加爲根節點的左孩子的右孩子,
而後對這個根節點的左孩子進行一個左旋轉操做,
左旋轉操做以後就以下圖所示,
就變成了新添加的這個節點比根節點要小而且比根節點的左孩子要小
的狀況,
那麼就對這個根節點進行一個右旋轉操做,
再來一個顏色翻轉操做便可。
// 中括號爲黑色節點,大括號爲紅色節點
// 原來是這樣的
// [42]
// /
// {37}
// \
// {40}
// 對根節點的左孩子 進行左旋轉後 染色後
// [42]
// /
// {40}
// /
// {37}
// 對根節點 進行右旋轉後 染色後
// [40]
// / \
// {37} {42}
//
// 對根節點 顏色翻轉後
// {40}
// / \
// [37] [42]
複製代碼
紅黑樹添加節點邏輯分佈圖
下圖中的邏輯只要分爲三種
是否須要左旋轉、右旋轉、顏色翻轉,
噹噹前節點的右孩子爲紅色而且當前節點的左孩子不爲紅色時,那麼就須要進行左旋轉;
噹噹前節點的左孩子爲紅色而且當前節點的左孩子的左孩子也爲紅色時,那麼就須要進行右旋轉;
噹噹前節點的左右孩子全都是紅色時,那麼就須要進行顏色翻轉;
這三種邏輯並不是是互斥的,而是相吸,每一次都須要進行這三種判斷,
下圖也是按照這樣的順序來進行步驟的執行的。
// 中括號爲黑色節點,大括號爲紅色節點
// 融合二節點
// 步驟一 步驟二 步驟三
// [null] [node] [node] [X]
// ----> ----> \ ----> /
// {X} {node}
// 首次添加節點 ----> 添加節點X ----> 左旋轉
//
// 狀況一 若是紅黑樹的根節點爲空
// 那麼 步驟一
// 狀況二 若是紅黑樹的根節點不爲空 新添加的節點小於根節點
// 那麼 步驟一 --> 步驟三
// 狀況三 若是紅黑樹的根節點不爲空 新添加的節點大於根節點
// 那麼 步驟一 --> 步驟二 --> 步驟三
// 融合三節點
//
// 步驟1 步驟2 步驟3 步驟4 步驟5
// [node] [node] [node] [Y] {Y}
// / ----> / ----> / ----> / \ ----> / \
//{X} {X} {Y} {X} {node} [X] [node]
// \ /
// {Y} {X}
// 添加節點Y ----> 左旋轉 ----> 右旋轉 ----> 顏色翻轉
//
// 狀況一 若是新添加的這個新節點 大於 根節點
// 那麼步驟1 --> 步驟4 --> 步驟5
// 狀況二 若是新添加的這個節點比根節點要小而且比根節點的左孩子要小
// 那麼步驟1 --> 步驟3 --> 步驟4 --> 步驟5
// 狀況三 若是新添加的這個節點比根節點要小而且比根節點的左孩子要大
// 那麼步驟1 --> 步驟2 --> 步驟3 --> 步驟4 --> 步驟5
複製代碼
紅黑樹添加節點時維護性質的時機
MyRedBlackTree
// 自定義紅黑樹節點 RedBalckTreeNode
class MyRedBalckTreeNode {
constructor(key = null, value = null, left = null, right = null) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
this.color = MyRedBlackTree.RED; // MyRedBlackTree.BLACK;
}
// @Override toString 2018-11-25-jwl
toString() {
return (
this.key.toString() +
'--->' +
this.value.toString() +
'--->' +
(this.color ? '紅色節點' : '綠色節點')
);
}
}
// 自定義紅黑樹 RedBlackTree
class MyRedBlackTree {
constructor() {
MyRedBlackTree.RED = true;
MyRedBlackTree.BLACK = false;
this.root = null;
this.size = 0;
}
// 判斷節點node的顏色
isRed(node) {
// 定義:空節點顏色爲黑色
if (!node) return MyRedBlackTree.BLACK;
return node.color;
}
// node x
// / \ 左旋轉 / \
// T1 x ---------> node T3
// / \ / \
// T2 T3 T1 T2
leftRotate(node) {
const x = node.right;
// 左旋轉過程
node.right = x.left;
x.left = node;
// 染色過程
x.color = node.color;
node.color = MyRedBlackTree.RED;
// 返回這個 x
return x;
}
// 顏色翻轉 當前節點變紅 左右孩子變黑
// 表示當前節點須要繼續向上進行融合
flipColors(node) {
node.color = MyRedBlackTree.RED;
node.left.color = MyRedBlackTree.BLACK;
node.right.color = MyRedBlackTree.BLACK;
}
// node x
// / \ 右旋轉 / \
// x T2 -------> y node
// / \ / \
// y T1 T1 T2
rightRotate(node) {
const x = node.left;
// 右翻轉過程
node.left = x.right;
x.right = node;
// 染色過程
x.color = node.color;
node.color = MyRedBlackTree.RED;
// 返回這個 x
return x;
}
// 比較的功能
compare(keyA, keyB) {
if (keyA === null || keyB === null)
throw new Error("key is error. key can't compare.");
if (keyA > keyB) return 1;
else if (keyA < keyB) return -1;
else return 0;
}
// 根據key獲取節點 -
getNode(node, key) {
// 先解決最基本的問題
if (!node) return null;
// 開始將複雜的問題 逐漸縮小規模
// 從而求出小問題的解,最後構建出原問題的解
switch (this.compare(node.key, key)) {
case 1: // 向左找
return this.getNode(node.left, key);
break;
case -1: // 向右找
return this.getNode(node.right, key);
break;
case 0: // 找到了
return node;
break;
default:
throw new Error(
'compare result is error. compare result : 0、 一、 -1 .'
);
break;
}
}
// 添加操做 +
add(key, value) {
this.root = this.recursiveAdd(this.root, key, value);
this.root.color = MyRedBlackTree.BLACK;
}
// 添加操做 遞歸算法 -
recursiveAdd(node, key, value) {
// 解決最簡單的問題
if (!node) {
this.size++;
return new MyRedBalckTreeNode(key, value);
}
// 將複雜的問題規模逐漸變小,
// 從而求出小問題的解,從而構建出原問題的答案
if (this.compare(node.key, key) > 0)
node.left = this.recursiveAdd(node.left, key, value);
else if (this.compare(node.key, key) < 0)
node.right = this.recursiveAdd(node.right, key, value);
else {
node.value = value;
return node;
}
// 紅黑樹性質的維護
// 是否須要左旋轉
// 若是當前節點的右孩子是紅色 而且 左孩子不是紅色
if (this.isRed(node.right) && !this.isRed(node.left))
node = this.leftRotate(node);
// 是否須要右旋轉
// 若是當前節點的左孩子是紅色 而且 左孩子的左孩子也是紅色
if (this.isRed(node.left) && this.isRed(node.left.left))
node = this.rightRotate(node);
// 是否須要顏色的翻轉
// 當前節點的左孩子和右孩子全都是紅色
if (this.isRed(node.left) && this.isRed(node.right))
this.flipColors(node);
// 最後返回這個node
return node;
}
// 刪除操做 返回被刪除的元素 +
remove(key) {
let node = this.getNode(this.root, key);
if (!node) return null;
this.root = this.recursiveRemove(this.root, key);
return node.value;
}
// 刪除操做 遞歸算法 +
recursiveRemove(node, key) {
// 解決最基本的問題
if (!node) return null;
if (this.compare(node.key, key) > 0) {
node.left = this.recursiveRemove(node.left, key);
return node;
} else if (this.compare(node.key, key) < 0) {
node.right = this.recursiveRemove(node.right, key);
return node;
} else {
// 當前節點的key 與 待刪除的key的那個節點相同
// 有三種狀況
// 1. 當前節點沒有左子樹,那麼只有讓當前節點的右子樹直接覆蓋當前節點,就表示當前節點被刪除了
// 2. 當前節點沒有右子樹,那麼只有讓當前節點的左子樹直接覆蓋當前節點,就表示當前節點被刪除了
// 3. 當前節點左右子樹都有, 那麼又分兩種狀況,使用前驅刪除法或者後繼刪除法
// 1. 前驅刪除法:使用當前節點的左子樹上最大的那個節點覆蓋當前節點
// 2. 後繼刪除法:使用當前節點的右子樹上最小的那個節點覆蓋當前節點
if (node.left === null) {
let rightNode = node.right;
node.right = null;
this.size--;
return rightNode;
} else if (node.right === null) {
let leftNode = node.left;
node.left = null;
this.size--;
return leftNode;
} else {
let predecessor = this.maximum(node.left);
node.left = this.removeMax(node.left);
this.size++;
// 開始嫁接 當前節點的左右子樹
predecessor.left = node.left;
predecessor.right = node.right;
// 將當前節點從根節點剔除
node = node.left = node.right = null;
this.size--;
// 返回嫁接後的新節點
return predecessor;
}
}
}
// 刪除操做的兩個輔助函數
// 獲取最大值、刪除最大值
// 之前驅的方式 來輔助刪除操做的函數
// 獲取最大值
maximum(node) {
// 不再能往右了,說明當前節點已是最大的了
if (!node.right) return node;
// 將複雜的問題漸漸減少規模,從而求出小問題的解,最後用小問題的解構建出原問題的答案
return this.maximum(node.right);
}
// 刪除最大值
removeMax(node) {
// 解決最基本的問題
if (!node.right) {
let leftNode = node.left;
node.left = null;
this.size--;
return leftNode;
}
// 開始化歸
node.right = this.removeMax(node.right);
return node;
}
// 查詢操做 返回查詢到的元素 +
get(key) {
let node = this.getNode(this.root, key);
if (!node) return null;
return node.value;
}
// 修改操做 +
set(key, value) {
let node = this.getNode(this.root, key);
if (!node) throw new Error(key + " doesn't exist.");
node.value = value;
}
// 返回是否包含該key的元素的判斷值 +
contains(key) {
return this.getNode(this.root, key) !== null;
}
// 返回映射中實際的元素個數 +
getSize() {
return this.size;
}
// 返回映射中是否爲空的判斷值 +
isEmpty() {
return this.size === 0;
}
// @Override toString() 2018-11-05-jwl
toString() {
let mapInfo = `MyBinarySearchTreeMap: size = ${this.size}, data = [ `;
document.body.innerHTML += `MyBinarySearchTreeMap: size = ${ this.size }, data = [ <br/><br/>`;
// 以非遞歸的前序遍歷 輸出字符串
let stack = new MyLinkedListStack();
stack.push(this.root);
if (this.root === null) stack.pop();
while (!stack.isEmpty()) {
let node = stack.pop();
if (node.left !== null) stack.push(node.left);
if (node.right !== null) stack.push(node.right);
if (node.left === null && node.right === null) {
mapInfo += ` ${node.toString()} \r\n`;
document.body.innerHTML += ` ${node.toString()} <br/><br/>`;
} else {
mapInfo += ` ${node.toString()}, \r\n`;
document.body.innerHTML += ` ${node.toString()}, <br/><br/>`;
}
}
mapInfo += ` ] \r\n`;
document.body.innerHTML += ` ] <br/><br/>`;
return mapInfo;
}
}
複製代碼
O(nlogn)
級別的,Main
// main 函數
class Main {
constructor() {
this.alterLine('RedBlackTree Comparison Area');
const n = 2000000;
const myBSTMap = new MyBinarySearchTreeMap();
const myAVLTree = new MyAVLTree();
const myRedBlackTree = new MyRedBlackTree();
let performanceTest1 = new PerformanceTest();
const random = Math.random;
let arrNumber = new Array(n);
// 循環添加隨機數的值
for (let i = 0; i < n; i++) arrNumber[i] = Math.floor(n * random());
this.alterLine('MyBSTMap Comparison Area');
const myBSTMapInfo = performanceTest1.testCustomFn(function() {
// 添加
for (const word of arrNumber)
myBSTMap.add(word, String.fromCharCode(word));
});
// 總毫秒數:4771
console.log(myBSTMapInfo + ' 節點個數:' + myBSTMap.getSize());
this.show(myBSTMapInfo + ' 節點個數:' + myBSTMap.getSize());
this.alterLine('MyAVLTree Comparison Area');
// const that = this;
const myAVLTreeInfo = performanceTest1.testCustomFn(function() {
for (const word of arrNumber)
myAVLTree.add(word, String.fromCharCode(word));
});
// 總毫秒數:6226
console.log(myAVLTreeInfo + ' 節點個數:' + myAVLTree.getSize());
this.show(myAVLTreeInfo + ' 節點個數:' + myAVLTree.getSize());
this.alterLine('MyRedBlackTree Comparison Area');
const myRedBlackTreeInfo = performanceTest1.testCustomFn(function() {
for (const word of arrNumber)
myRedBlackTree.add(word, String.fromCharCode(word));
});
// 總毫秒數:6396
console.log(
myRedBlackTreeInfo + ' 節點個數:' + myRedBlackTree.getSize()
);
this.show(
myRedBlackTreeInfo + ' 節點個數:' + myRedBlackTree.getSize()
);
}
// 將內容顯示在頁面上
show(content) {
document.body.innerHTML += `${content}<br /><br />`;
}
// 展現分割線
alterLine(title) {
let line = `--------------------${title}----------------------`;
console.log(line);
document.body.innerHTML += `${line}<br /><br />`;
}
}
// 頁面加載完畢
window.onload = function() {
// 執行主函數
new Main();
};
複製代碼