JS 實現二叉查詢樹(Binary Search Tree)
阿新 • • 發佈:2018-12-05
知識點
- 二叉查詢樹,也稱二叉搜尋樹、有序二叉樹(英語:ordered binary tree)是指一棵空樹
- 任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
- 任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
- 任意節點的左、右子樹也分別為二叉查詢樹;
- 沒有鍵值相等的節點;
- 二叉查詢樹相比於其他資料結構的優勢在於查詢、插入的時間複雜度較低。為O(log n)。
- 二叉查詢樹是基礎性資料結構,用於構建更為抽象的資料結構,如集合、multiset、關聯陣列等。
實現程式碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>二叉查詢樹</title> </head> <body> <script> // 單個節點物件 class Node { constructor (data, left, right) { this.data = data; this.left = left; this.right = right; } } // 樹 class BinarySearchTree { constructor () { this.root = null; } // 插入成功返回樹 insert (data) { let cNode = new Node(data, null, null); // 空樹 if (!this.root) { this.root = cNode; return ; } // 非空樹 let currentNode = this.root; let parent = null; // 遍歷 while(1) { // 得到一個指向 即將改變 或 其子節點將要被改變 的節點的 變數 parent = currentNode; // 左子樹 if (data < currentNode.data) { // currentNode 指向為空,賦值到currentNode無效 /* currentNode = parent.left; if (currentNode === null) { currentNode = n; break; }*/ currentNode = currentNode.left; if (currentNode === null) { parent.left = cNode; break } } // 右子樹 else if ( data > currentNode.data ) { // currentNode 指向為空,賦值到currentNode無效 /*currentNode = parent.right; if (currentNode === null) { currentNode = n; break; }*/ currentNode = currentNode.right; if (currentNode === null) { parent.right = cNode; break; } } // 相等 else { break; } } } // 傳入陣列,建立樹 create (arr) { if (!arr.length) { this.root = null; }else { let length = arr.length; for (let i = 0; i < length; i++) { console.log() this.insert(arr[i]); } } } // 刪除 remove (data) { this.root = this.removeNodeByData(this.root, data); } // 返回刪除對應值後的 "node" removeNodeByData (node, data) { if (node === null) { return null; } // 資料等於傳入樹的根節點資料 if (data === node.data) { // 子節點都為空 if (node.left === null && node.right === null) { // 返回為空 樹為空 return null; } // 左節點為空 if (node.left === null){ // 刪除的資料等於根節點的資料,且根節點左節點為空,刪除根節點,返回右節點 return node.right } // 右節點為空 if (node.right === null){ return node.left; } // 思路:子節點都不為空的處理函式,找到刪除節點的中序遍歷的直接前驅(或直接後驅)結點,用該結點來替換要刪除的節點,再刪除該節點 // 得到直接的後驅節點(節點的右子樹最左邊的節點,或最右邊的節點) let getAftNode = function (node) { if (node.left === null && node.right === null) { return node; } if (node.left !== null) { return getAftNode(node.left); } if (node.right !== null) { return node.right; } } //相等,且左右節點都不為空 let tempNode = getAftNode(node.right); // 要刪除的節點的值等於 其直接後繼的值 node.data = tempNode.data; // 刪除 要刪除的節點 的直接後繼 node.right = this.removeNodeByData(node.right, tempNode.data); /* { // 得到直接的前驅節點(節點的左子樹最右邊的節點,或最左邊的節點) let getPreNode = function (node) { if (node.left === null && node.right === null) { return node } if (node.right !== null) { return getPreNode(node.right) } if (node.left !== null) { return node.left } } let tempNode = getPreNode(node.left); node.data = tempNode.data; node.left = this.removeNodeByData(node.left, tempNode.data); }*/ return node; } else if (data < node.data) { node.left = this.removeNodeByData(node.left, data); // 當前的節點不變 return node; }else { node.right = this.removeNodeByData(node.right, data); // 當前的節點不變 return node } } // 非遞迴查詢, 返回查詢到的節點 findByNonRecur(data) { let current = this.root; let tagNode = null; while (current !== null) { console.log(current); if (data === current.data) { tagNode = current; break; }else if (data < current.data) { current = current.left; } else if (data > current.data) { current = current.right; } } // 查詢到返回節點,沒查詢返回null return tagNode } // 遞迴查詢,返回節點 findByRecur (data) { // let current = node||this.root; --- 造成無限迴圈 let current = this.root; return (function _selfCall(data, current) { if (current === null) { return null; } if (current.data === data) { return current }else if (data < current.data) { current = current.left; // 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them // return arguments.callee(data, current) return _selfCall(data, current) } else { current = current.right; // 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them // return arguments.callee(data, current) return _selfCall(data, current) } })(data, current) } // 獲取最大值 findMax(){ let current = this.root; while(current.right !== null) { current = current.right; } return current.data } // 獲取最小值 findMin(){ let current = this.root; while(current.left!==null){ current = current.left } return current.data } // 先序遍歷 -- 根、左、右 preTravel(node){ let preTravelArr = []; (function _preTravel (node) { if (node !== null) { preTravelArr.push(node.data); _preTravel(node.left); _preTravel(node.right); } })(node) return preTravelArr; } // 中序遍歷 -- 左、根、右 midTravel(node){ let midTravelArr = []; (function _midTravel (node) { if (node !== null) { _midTravel(node.left); midTravelArr.push(node.data); _midTravel(node.right); } })(node) return midTravelArr; } // 後序遍歷 -- 左、右、根 aftTravel(node){ let aftTravelArr = []; (function _aftTravel (node) { if (node !== null) { _aftTravel(node.left); _aftTravel(node.right); aftTravelArr.push(node.data); } })(node) return aftTravelArr; } } let BSTree = new BinarySearchTree(); // 建立樹 BSTree.create([62,58,47,35,29,37,36,51,49,48,50,56,88,73,99,93]); // 操作 </script> </body> </html>