觀點
二叉樹
(Binary Tree)是另一種樹型構造,它的特點是每一個結點最多只要兩棵子樹(即二叉樹中不存在度大於 2 的結點),而且,二叉樹的子樹有擺布之分(其序次不能恣意倒置。)
性子
- 二叉樹的第 i 層上最多有 2 的(i-1)方個節點。(i>=1)
- 深度為 k 的樹最多有 2 的 k 次方-1 個節點。(k>=1)
- 對任何一棵二叉樹 T,假如其終端結點數為 n0,度為 2 的結點數為 n2,則 n0 = n2 + 1;
_ 一棵深度為 k 且有 2 的 k 次方-1 個結點的二叉樹稱為滿二叉樹
。
_ 深度為 k 的,有 n 個結點的二叉樹,當且僅當其每一個結點都與深度為 k 的滿二叉樹中編號從 1 至 n 的結點一一對應時,稱之為完整二叉樹
。
<!– more –>
初始化二叉樹構造
// 建立節點
class Node {
constructor(key) {
this.key = key
this.left = null
this.right = null
}
}
// 建立二叉樹花樣
class BinaryTree {
constructor(...args) {
this.root = null
// 初始化順次插進去數據
args.forEach(key => {
this.insert(key)
})
}
// 實例化
static create(args) {
return new BinaryTree(...args)
}
}
新增要領
思緒:推斷插進去的節點和當前節點,若大於當前節點,去右子樹插進去,不然左子樹插進去。
insert(key) {
const newNode = new Node(key);
const insertNode = function(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) {
// 假如root不存在,將newNode設為根節點
this.root = newNode
} else {
insertNode(this.root, newNode)
}
}
挪用情勢
const nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13]
const binaryTree = BinaryTree.create(nodes)
binaryTree.insert(55)
console.log(binaryTree.root)
遍歷要領
二叉樹
的遍歷(traversing binary tree)是指從根結點動身,依據某種序次順次接見二叉樹中所有結點,使得每一個結點被接見一次且僅被接見一次。
前序遍歷(DLR)
起首接見根結點,然後遍歷左子樹,末了遍歷右子樹。簡記根-左-右。
- 用處:用於複製一顆二叉樹
- 算法思緒
若二叉樹為空,則遍歷完畢;不然 1. 接見根結點 2. 先序遍歷左子樹(遞歸挪用本算法) 3. 先序遍歷右子樹(遞歸挪用本算法)
// 前序遍歷
preOrderTraverse () {
const preOrderTraverse = node => {
if (node !== null) {
console.log(node.key)
preOrderTraverse(node.left)
preOrderTraverse(node.right)
}
}
preOrderTraverse(this.root)
}
中序遍歷(LDR)
起首遍歷左子樹,然後接見根結點,末了遍歷右子樹。簡記左-根-右。
- 用處:用於從小到大排序二叉樹
- 算法思緒
若二叉樹為空,則遍歷完畢;不然 1. 中序遍歷左子樹(遞歸挪用本算法) 2. 接見根結點 3. 中序遍歷右子樹(遞歸挪用本算法)
//運用遞歸體式格局完成中序遍歷
inOrderTraverse () {
const inOrderTraverseNode = node => {
if (node !== null) {
// 假如當前節點非空,則接見左子樹
inOrderTraverseNode(node.left)
// 直到接見到最底部的左子樹才進入callback,每一個節點都邑有callback
console.log(node.key)
// 此時已經是最底部的左子樹
inOrderTraverseNode(node.right)
}
// 詮釋:起首進入8,發明左側有3,實行左側遍歷,遍歷完后實行3的回調,在實行3的右側的回調,
}
inOrderTraverseNode(this.root)
}
後序遍歷(LRD)
起首遍歷左子樹,然後遍歷右子樹,末了接見根結點。簡記左-右-根。
- 算法思緒
若二叉樹為空,則遍歷完畢;不然 1. 後序遍歷左子樹(遞歸挪用本算法); 2. 後序遍歷右子樹(遞歸挪用本算法) ; 3. 接見根結點 。
postOrderTraverse () {
const postOrderTraverse = node => {
if (node !== null) {
postOrderTraverse(node.left)
postOrderTraverse(node.right)
console.log(node.key)
}
}
postOrderTraverse(this.root)
}
查找算法
查找最大值
思緒:傳入二叉樹,尋覓右子樹,直到找到不存在右子樹的節點。
// 查找最大值
max () {
const maxNode = node => {
if (node !== null) {
if (node.right) {
return maxNode(node.right)
} else {
return node.key
}
}
}
return maxNode(this.root)
}
查找最小值
思緒:傳入二叉樹,尋覓左子樹,直到找到不存在左子樹的節點。
// 查找最小值
min () {
const minNode = node => {
if (node !== null) {
if (node.left) {
return minNode(node.left)
} else {
return node.key
}
}
}
return minNode(this.root)
}
查找恣意值
思緒:依據傳入的 key 與當前節點比較,假如大於當前 key 則去右子樹查找,不然去左子樹查找。
// 查找指定值
search (key) {
const searchNode = function(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)
}
刪除算法
思緒:假如刪除的 key 小於當前節點,去左子樹種查找,不然去右子樹查找。找到節點后,推斷是不是存在子節點,若不存在,直接刪除,若只存在左節點或許右節點,將當前節點替換為它的子節點。若擺布節點都存在,將右節點中的最小值(左子樹)移除並替換為刪除的節點位置(為了滿足二叉樹的左子樹小於右子樹)
remove (key) {
// 用於查找最小節點
const findMinNode = node => {
if (node) {
// 假如node的左孩子存在
while (node && node.left !== null) {
// 將node設為node的左孩子再次進入輪迴
node = node.left
}
// 直到返回沒有左孩子的node
return node
}
}
const removeNode = (node, key) => {
if (node === null) {
return false
}
if (key < node.key) {
// 當前node大於刪除key,去左孩子中查找
node.left = removeNode(node.left, key)
return node
} else if (key > node.key) {
// 當前node小於刪除key,去右孩子中查找
node.right = removeNode(node.right, key)
} else {
// key和當前node相稱
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
}
// 同時存在左孩子和右孩子
// 找出右側的最小值
const aux = findMinNode(node.right)
// 將最小值替換為刪除的key
node.key = aux.key
// 在右孩子中刪除最小值
node.right = removeNode(node.right, aux.key)
return node
}
}
const result = removeNode(this.root, key)
console.log(result)
}