生成一棵二叉樹
二叉樹實現原理
把第一位當做根節點,比根節點小的數放在左子樹上,比根節點大的數放到右子樹上,以此類推。
把下面陣列生成一個二叉樹:
let nodes = [8,3,6,4,9,11,2,5,7];
結構如下
生成的二叉樹物件如下
let tree = { key: 8, left: { key: 3, left: { key: 2, left: null, right: null }, right: { key: 6, left: { key: 4, left: null, right: { key: 5, left: null, right: null } }, right: { key: 7, left: null, right: null } } } right: { key: 9, left: null, right: { key: 11, left: null, right: null } } }複製程式碼
生成二叉樹實現程式碼
//API:
//insert新增一個子樹,傳值Number
//bulkInsert批量新增子樹,傳值Array
//showTree返回二叉樹物件
class BinaryTree {
constructor(tree = []) {
this.root = null;//樹根
this.Node = key => {
//生成一個新的子樹
let _obj = Object.create(null, {});
_obj.key = key;
_obj.left = null;
_obj.right = null;
return _obj;
}
//初始化二叉樹
if (typeof tree === 'number') {
this.insert(tree);
} else if (Array.isArray(tree)) {
this.bulkInsert(tree)
} else {
console.error('請輸入Number型別或者Array型別的引數')
}
}
insert(key) {
//新增一個新子樹
let newNode = this.Node(key);
let _insertNode = (node, newNode) => {
//判斷新二叉樹的值和原有節點的值
if (newNode.key < node.key) {
if (node.left === null) {
//判斷左節點是否為空
node.left = newNode;
} else {
_insertNode(node.left, newNode)
}
} else {
if (node.right === null) {
//判斷右節點是否為空
node.right = newNode;
} else {
_insertNode(node.right, newNode)
}
}
}
if (this.root === null) {
//如果沒有根節點,那麼把傳入的值當根節點
this.root = newNode;
} else {
//如果有根節點,那麼把傳入的值插到二叉樹上
_insertNode(this.root, newNode);
}
}
bulkInsert (nodes) {
nodes.forEach(key => {
//遍歷陣列,插入子樹
this.insert(key);
})
}
showTree () {
//返回二叉樹物件
return this.root;
}
}
let nodes = [8,3,6,4,9,11,2,5,7];
let binaryTree = new BinaryTree(nodes);
let tree = binaryTree.showTree();複製程式碼
先序遍歷、中序遍歷、後序遍歷
- 先序遍歷
- 根左右
- 中序遍歷
- 左根右
- 後序遍歷
- 左右根
class BinaryTree {
......//生成樹的程式碼
inOrderTraverse (fn) {
//中序遍歷,傳入一個回撥函式
let inOrderTraverseNode = (node, callback) => {
if (node !== null) {
inOrderTraverseNode(node.left, callback);
callback(node.key);
inOrderTraverseNode(node.right, callback);
}
}
inOrderTraverseNode(this.root, fn)
}
preOrderTraverse (fn) {
//先序遍歷,傳入一個回撥函式
let preOrderTraverseNode = (node, callback) => {
if (node !== null) {
callback(node.key);
preOrderTraverseNode(node.left, callback);
preOrderTraverseNode(node.right, callback);
}
}
preOrderTraverseNode(this.root, fn)
}
postOrderTraverse (fn) {
//先序遍歷,傳入一個回撥函式
let postOrderTraverseNode = (node, callback) => {
if (node !== null) {
postOrderTraverseNode(node.left, callback);
postOrderTraverseNode(node.right, callback);
callback(node.key);
}
}
postOrderTraverseNode(this.root, fn)
}
}
let nodes = [8,3,6,4,9,11,2,5,7];
let binaryTree = new BinaryTree(nodes);
let arr1 = [],
arr2 = [],
arr3 = [];
binaryTree.inOrderTraverse(key => {
arr1.push(key);//中序遍歷[2, 3, 4, 5, 6, 7, 8, 9, 11]
})
binaryTree.preOrderTraverse(key => {
arr2.push(key);//先序遍歷[8, 3, 2, 6, 4, 5, 7, 9, 11]
})
binaryTree.postOrderTraverse(key => {
arr3.push(key);//後序遍歷[2, 5, 4, 7, 6, 3, 11, 9, 8]
})複製程式碼
二叉樹節點查詢
- 查詢最大值、最小值
class BinaryTree {
......//生成樹的程式碼與三種遍歷程式碼
min() {
let node = this.root;
if (node) {
//迴圈遍歷左子樹
while (node && node.left !== null) {
node = node.left;
}
return node.key;
}
}
max() {
let node = this.root;
if (node) {
//迴圈遍歷右子樹
while (node && node.right !== null) {
node = node.right;
}
return node.key;
}
}
}
let nodes = [8,3,6,4,9,11,2,5,7];
let binaryTree = new BinaryTree(nodes);
let min = binaryTree.min();//2
let max = binaryTree.max();//11複製程式碼
- 查詢二叉樹中節點是否存在
class BinaryTree {
......//生成樹的程式碼與三種遍歷程式碼
search(key) {
let searchNode = (node, key) => {
if (node === null) {
return false;
}
if (key < node.key) {
//當查詢的值小於當前節點的值,則遞迴其左子樹
return searchNode(node.left, key);
} else if (key > node.key){
//當查詢的值大於當前節點的值,則遞迴其右子樹
return searchNode(node.right, key);
} else {
return true;
}
}
return searchNode(this.root, key)
}
}
let nodes = [8,3,6,4,9,11,2,5,7];
let binaryTree = new BinaryTree(nodes);
let inTree1 = binaryTree.showTree(2);//true
let inTree2 = binaryTree.showTree(1);//false複製程式碼
二叉樹節點刪除
- 需要判斷這個節點是否還有子樹,有三種情況,無子樹,有單子樹,有雙子樹。
class BinaryTree {
......//生成樹的程式碼與三種遍歷程式碼
remove(key) {
let findMinNode = (node, key) => {
//查詢最小子節點
let node = node || this.root;
if (node) {
while (node && node.left !== null) {
node = node.left;
}
return node;
}
return null;
}
let removeNode = (node, key) => {
if (node === null) {
//如果為null,返回null
return null
}
if (key < node.key) {
//如果值小於當前節點值,遞迴其左子樹
node.left = removeNode(node.left, key);
return node;
} else if (key > node.key) {
//如果值大於當前節點值,遞迴其右子樹
node.right = removeNode(node.right, key);
return node;
} else {
//如果值等於當前節點值,做該節點刪除操作
if (node.left === null && node.right === null) {
//如果該節點沒有左右子樹,直接使其為null
node = null;
return node;
}
if (node.left === null) {
//如果該節點只有右子樹,則將該節點指向它的右子樹
node = node.right;
return node;
} else if (node.right === null) {
//如果該節點只有左子樹,則將該節點指向它的左子樹
node = node.left;
return node;
}
if (node.left !== null && node.right !== null) {
//如果該節點有左右子樹,則把找到它的右子樹的最小子節點,並使該節點的值等於它的右子樹的最小子節點的值,然後刪除它的右子樹的最小子節點
let aux = findMinNode(node.right);
node.key = aux;
node.right = removeNode(node.right, aux.key);
return node;
}
}
}
this.root = removeNode(this.root, key)
}
}
let nodes = [8,3,6,4,9,11,2,5,7];
let binaryTree = new BinaryTree(nodes);複製程式碼
JS二叉樹完整程式碼
class BinaryTree {
constructor(tree = []) {
this.root = null;//樹根
this.Node = key => {
//生成一個新的子樹
let _obj = Object.create(null, {});
_obj.key = key;
_obj.left = null;
_obj.right = null;
return _obj;
}
//初始化二叉樹
if (typeof tree === 'number') {
this.insert(tree);
} else if (Array.isArray(tree)) {
this.bulkInsert(tree)
} else {
console.error('請輸入Number型別或者Array型別的引數')
}
}
insert(key) {
//新增一個新子樹
let newNode = this.Node(key);
let _insertNode = (node, newNode) => {
//判斷新二叉樹的值和原有節點的值
if (newNode.key < node.key) {
if (node.left === null) {
//判斷左節點是否為空
node.left = newNode;
} else {
_insertNode(node.left, newNode)
}
} else {
if (node.right === null) {
//判斷右節點是否為空
node.right = newNode;
} else {
_insertNode(node.right, newNode)
}
}
}
if (this.root === null) {
//如果沒有根節點,那麼把傳入的值當根節點
this.root = newNode;
} else {
//如果有根節點,那麼把傳入的值插到二叉樹上
_insertNode(this.root, newNode);
}
}
bulkInsert (nodes) {
nodes.forEach(key => {
//遍歷陣列,插入子樹
this.insert(key);
})
}
showTree () {
//返回二叉樹物件
return this.root;
}
inOrderTraverse (fn) {
let inOrderTraverseNode = (node, callback) => {
if (node !== null) {
inOrderTraverseNode(node.left, callback);
callback(node.key);
inOrderTraverseNode(node.right, callback);
}
}
inOrderTraverseNode(this.root, fn)
}
preOrderTraverse (fn) {
let preOrderTraverseNode = (node, callback) => {
if (node !== null) {
callback(node.key);
preOrderTraverseNode(node.left, callback);
preOrderTraverseNode(node.right, callback);
}
}
preOrderTraverseNode(this.root, fn)
}
postOrderTraverse (fn) {
let postOrderTraverseNode = (node, callback) => {
if (node !== null) {
postOrderTraverseNode(node.left, callback);
postOrderTraverseNode(node.right, callback);
callback(node.key);
}
}
postOrderTraverseNode(this.root, fn)
}
min() {
let node = this.root;
if (node) {
while (node && node.left !== null) {
node = node.left;
}
return node.key;
}
}
max() {
let node = this.root;
if (node) {
while (node && node.right !== null) {
node = node.right;
}
return node.key;
}
}
search(key) {
let searchNode = (node, key) => {
if (node === null) {
return false;
}
if (key < node.key) {
return searchNode(node.left, key);
} else if (key > node.key){
return searchNode(node.right, key);
} else {
return true;
}
}
return searchNode(this.root, key)
}
remove(key) {
let findMinNode = (node, key) => {
let node = node || this.root;
if (node) {
while (node && node.left !== null) {
node = node.left;
}
return node;
}
return null;
}
let removeNode = (node, key) => {
if (node === null) {
return null
}
if (key < node.key) {
node.left = removeNode(node.left, key);
return node;
} else if (key > node.key) {
node.right = removeNode(node.right, key);
return node;
} else {
if (node.left === null && node.right === null) {
node = null;
return node;
}
if (node.left === null) {
node = node.right;
return node;
} else if (node.right === null) {
node = node.left;
return node;
}
if (node.left !== null && node.right !== null) {
let aux = findMinNode(node.right);
node.key = aux;
node.right = removeNode(node.right, aux.key);
return node;
}
}
}
this.root = removeNode(this.root, key)
}
}
let nodes = [8,3,6,4,9,11,2,5,7];
let binaryTree = new BinaryTree(nodes);複製程式碼