二維拓撲結構(圖)
- 二叉樹 多叉樹 都是基於拓撲結構生成的
// 拓撲結構
function Node (value) {
this.value = value
this.neighbor = []
}
var node1 = new Node(1)
var node2 = new Node(2)
var node3 = new Node(3)
var node4 = new Node(4)
node1.neighbor.push(node2, node3)
node2.neighbor.push(node1, node4)
node3.neighbor.push(node1, node4)
node4.neighbor.push(nod2, node3)
複製程式碼
樹形結構(有向無環圖)
- 樹是圖的一種
- 樹有一個根節點
- 樹沒有環形結構(迴路)
- 度: 樹的最多叉的節點有多少叉,就有多少度
- 深度: 樹最深有多少層,就是多少深度
二叉樹
- 樹的度最多為二的樹
-
滿二叉樹
- 所有的葉子節點都在最底層
- 每個非葉子節點都有兩個子節點
-
完全二叉樹
國內定義
- 葉子節點都在最後一層或者倒數第二層
- 葉子節點都向左聚攏
國際定義
- 葉子節點都在最後一層或者倒數第二層
- 如果有葉子節點,就必須有兩個葉子節點
二叉樹的遍歷
- 前序遍歷(前根次序遍歷)先列印當前的,再列印左邊的,再列印右邊的
- 中序遍歷(中根次序遍歷)先列印左邊的,先列印當前的,再列印右邊的
- 後序遍歷(後根次序遍歷)先列印左邊的,再列印右邊的,先列印當前的
// 構建二叉樹
function Node(val) {
this.value = val
this.left = null
this.right = null
}
var a = new Node('a')
var b = new Node('b')
var c = new Node('c')
var d = new Node('d')
var e = new Node('e')
var f = new Node('f')
var g = new Node('g')
a.left = c
a.right = b
b.left = e
b.right = f
c.left = g
複製程式碼
- 二叉樹演算法
// 前序遍歷
function qianxu (node) {
if (node === null) return
console.log(node.val)
qianxu(node.left)
qianxu(node.right)
}
// 中序遍歷
function zhongxu (node) {
if (node === null) return
qianxu(node.left)
console.log(node.val)
qianxu(node.right)
}
// 後序遍歷
function houxu (node) {
if (node === null) return
qianxu(node.left)
qianxu(node.right)
console.log(node.val)
}
複製程式碼
中序遍歷 根節點的左邊是左子樹;
前序遍歷 第一個是根節點;
後序遍歷 最後一個是根節點
用中序遍歷確認左右子樹,前後序遍歷確認根節點
// 根據前序後序 還原二叉樹
var qian = ['a', 'b', 'e', 'f', 'c', 'g', ]
var zhong = ['b', 'e', 'f', 'a', 'c', 'g', ]
var num = 0
function huanyuan(qian, zhong) {
if (qian == null || zhong == null || qian.length == 0 || zhong.length == 0 || qian.length != zhong.length) return null;
var root = new Node(qian[0]) // 建立二叉樹 根據前序找到根節點
var zhongIdx = zhong.indexOf(root.val) // 在中序中找到根節點位置
var qLeft = qian.slice(1, zhongIdx + 1) // 前序左子樹
var qRight = qian.slice(zhongIdx + 1, qian.length) // 前序右子樹
var zLeft = zhong.slice(0, zhongIdx) // 中序左子樹
var zRight = zhong.slice(zhongIdx + 1, zhong.length) // 中序右子樹
root.right = huanyuan(qLeft, zLeft)
root.left = huanyuan(qRight, zRight)
return root
}
var root = huanyuan(qian, zhong)
複製程式碼
二叉樹的搜尋
- 樹的搜尋 圖的搜尋 爬蟲邏輯 搜尋引擎爬蟲邏輯
- 深度優先搜尋:更適合探索未知 往深處搜尋
- 廣度優先搜尋:更適合搜尋局域 一層一層搜尋
對於二叉樹來說,深度優先搜尋和前序遍歷的順序是一樣的 廣度優先搜尋和中序遍歷的順序是一樣的
// 深度優先搜尋
/**
*實現一顆二叉樹
*/
// 搜尋 f 在不在這個二叉樹中
function deepSearch (node, target) {
if (node == null) return false
if (node.value == target) return true
// 向更深層遞迴搜尋
var left = deepSearch(node.left, target)
var right = deepSearch(node.right, target)
return left || right
}
/**
* 二叉樹的廣度優先 每一層搜尋完了再向下一層搜尋
*/
function widthSearch(nodeList, target) {
if (nodeList == null || nodeList.length == 0) return false
var childList = []
for (var i = 0; i < nodeList.length; i++) {
if (nodeList[i] != null && nodeList[i].value == target) {
return true
} else {
childList.push(nodeList[i].left)
childList.push(nodeList[i].right)
}
}
return widthSearch(childList, target)
}
/**
* 二叉樹比較
* 左子樹和右子樹互換 不算 同一棵樹的情況
*/
function compareTree(tree1, tree2){
if (tree1 == tree2) return true // 同一棵樹
if (tree1.value == tree2.value) {
var left = compareTree(tree1.left, tree2.left)
var right = compareTree(tree1.right, tree2.right)
return left && right
}
return false
}
/**
* 二叉樹比較
* 左子樹和右子樹互換 算 同一棵樹的情況
*/
function compareTree(tree1, tree2){
if (tree1 == tree2) return true
if (tree1.value == tree2.value) {
return compareTree(tree1.left, tree2.left) && compareTree(tree1.right, tree2.right)
|| compareTree(tree1.left, tree2.right) && compareTree(tree1.right, tree2.left)
}
return false
}
複製程式碼
二叉樹diff演算法
知道樹結構新增了什麼,刪除了什麼,修改了什麼
/**
* 二叉樹的diff演算法
*/
function diffList(tree1, tree2, diffLists = []) {
if (tree1 == tree2) return diffLists
// 修改 刪除 新增 三種情況
if (tree1.value != tree2.value) { // 修改
diffLists.push({type: 'update', origin: tree1, now: tree2})
// 修改需要繼續向下遞迴,有可能子節點沒有修改
diffList(tree1.left, tree2.left)
diffList(tree1.right, tree2.right)
} else if (tree1 != null && tree2 == null) { // 刪除
diffLists.push({type: 'delete', origin: tree1, now: null})
} else if (tree1 == null && tree2 != null) { // 新增
diffLists.push({type: 'add', origin: null, now: tree2})
} else { // 相同則遍歷子節點
diffList(tree1.left, tree2.left)
diffList(tree1.right, tree2.right)
}
return diffLists
}
複製程式碼