二叉树使用场景
- 数据结构:二叉树是一种常见的数据结构,可以用于存储和组织数据。例如,二叉搜索树是一种特殊的二叉树,它可以快速地查找、插入和删除数据。
- 排序算法:二叉树可以用于实现一些排序算法,例如快速排序和归并排序。在这些算法中,二叉树被用来将数据划分为独立的子集,并对这些子集进行排序。
- 表达式求值:二叉树可以用于表示数学表达式,并对其进行求值。在这种情况下,二叉树的每个节点表示一个运算符或操作数,而节点的子节点表示操作数。
- 实现决策树:在机器学习中,决策树是一种重要的算法,它可以用于分类和回归问题。在这种情况下,二叉树被用来表示决策过程,每个节点表示一个决策条件,而子节点表示不同的结果。
- 数据压缩:在数据压缩中,二叉树可以用于编码和解码数据。在这种情况下,二叉树的每个节点表示一个符号或一组符号的编码,而子节点表示编码的上下文。
编译器:在编译器中,二叉树被用来表示源代码的结构,并对源代码进行语法分析和语义分析。在这种情况下,二叉树的每个节点表示一个语法或语义结构,而子节点表示语法或语义规则。
用代码描述二叉树
const TreeNode = function(value) {
this.value = value;
this.left = null;
this.right = null;
}
const a = new TreeNode('A');
const b = new TreeNode('B');
const c = new TreeNode('C');
const d = new TreeNode('D');
const e = new TreeNode('E');
const f = new TreeNode('F');
const g = new TreeNode('G');
a.left = b;
a.right = c;
b.left = d;
b.right = e;
c.left = f;
c.right = g;
console.log("构建的二叉树如下:", a);
二叉树遍历
前序遍历
- 概念: 根节点 -> 左子树 -> 右子树
- 图1中二叉树前序遍历:[‘A’,’ B’,’ D’, ’ E’, ’ C’, ’ F’, ’ G’]
后序遍历
- 概念: 左子树 -> 右子树 -> 根节点
- 图1中二叉树后序遍历: [’ D’, ’ E’, ’ B’, ’ F’, ’ G’, ’ C’, ‘A’]
中序遍历
- 概念: 左子树 -> 根节点 -> 右子树
- 图1中二叉树后序遍历:[’ D’, ’ B’, ’ C’, ‘A’, ’ F’, ’ C’, ’ G’]
二叉树还原
- 注意:有中序遍历情况 + 前序或者后序遍历才能还原二叉树
- 前序遍历+中序遍历 还原二叉树
function toTreeFromQianzhong(qian, zhong) {
if(qian !== null && qian.length > 0 && zhong !== null && zhong.length > 0 && qian.length === zhong.length){
const node = new TreeNode(qian[0]);
const nodePos = zhong.indexOf(node.value);
const zLeft = zhong.slice(0, nodePos);
const zRight = zhong.slice(nodePos+1, zhong.length);
const leftEnd = 1+ zLeft.length;
const qLeft = qian.slice(1, leftEnd);
const qRight = qian.slice(leftEnd, qian.length);
node.left = toTreeFromQianzhong(qLeft, zLeft);
node.right = toTreeFromQianzhong(qRight, zRight);
return node;
}else{
return null;
}
}
const qianList = ['A',' B',' D', ' e', ' C', ' F', ' G'];
const zhongList = [' D', ' B', ' C', 'A', ' F', ' C', ' G'];
const qzRoot = toTreeFromQianzhong(qianList, zhongList);
console.log("前序中序还原二叉树", qzRoot);
function toTreeFromHouzhong(hou, zhong) {
if(hou !== null && hou.length > 0 && zhong !== null && zhong.length > 0 && hou.length === zhong.length){
const node = new TreeNode(hou[hou.length - 1]);
const nodePos = zhong.indexOf(node.value);
const zLeft = zhong.slice(0, nodePos);
const zRight = zhong.slice(nodePos+1, zhong.length);
const leftEnd = 0 + zLeft.length;
const hLeft = hou.slice(0, leftEnd);
const hRight = hou.slice(leftEnd, hou.length - 1);
node.left = toTreeFromHouzhong(hLeft, zLeft);
node.right = toTreeFromHouzhong(hRight, zRight);
return node;
}else{
return null;
}
}
const zhongList = [' D', ' B', ' C', 'A', ' F', ' C', ' G'];
const houList = [' D', ' e', ' B', ' F', ' G', ' C', 'A'];
const hzRoot = toTreeFromHouzhong(houList, zhongList);
console.log("后序、中序还原二叉树", hzRoot);
二叉树diff算法(区分左右子树)
function lrDiffNode(node1, node2, diff) {
if(node1 === null && node2 === null){
return diff;
}else if(node1 !== null && node2 === null){
diff.push({type: 'delete', old: node1, cur: node2});
return diff;
}else if(node1 === null && node2 !== null){
diff.push({type: 'add', old: node1, cur: node2});
return diff;
}else{
if(node1 === node2){
return diff;
}else{
const diffLr = ()=>{
lrDiffNode(node1.left, node2.left, diff);
lrDiffNode(node1.right, node2.right, diff);
};
if(node1.value === node2.value){
diffLr();
return diff;
}else{
diff.push({type: 'modify', old: node1, cur: node2});
diffLr();
return diff;
}
}
}
}
const qianList1= ['A',' B',' D', ' e', ' C', ' G'];
const zhongList1 = [' D', ' B', ' C', 'A', ' C', ' G'];
const houList1 = [' D', ' e', ' B', ' G', ' C', 'A'];
const newTreeRoot = toTreeFromQianzhong(qianList1, zhongList1);
console.log("diff: 删除f节点", lrDiffNode(a, newTreeRoot, []));
const qianList_modify_b_h = ['A','h',' D', ' e', ' C', ' F', ' G'];
const zhongList_modify_b_h = [' D', 'h', ' C', 'A', ' F', ' C', ' G'];
const houList_modify_b_h = [' D', ' e', 'h', ' F', ' G', ' C', 'A'];
const treeRoot_b_h = toTreeFromHouzhong(houList_modify_b_h, zhongList_modify_b_h);
console.log("diff: b节点修改为h", lrDiffNode(a, treeRoot_b_h, []));
二叉树查找
const findNode = function(root, findValue) {
if(root!== null){
if(findValue !== null && findValue !== void 0){
console.log("深度优先过程:" + root.value);
if(root.value === findValue){
return root;
}else{
return findNode(root.left, findValue) || findNode(root.right, findValue);
}
}else{
return null;
}
}else{
return null;
}
}
console.log("find[深度优先]:在tree中找出g元素", findNode(a, ' F'));
const findNodeByScope = function(nodes, findValue) {
if(nodes!== null && nodes.length > 0){
const nextFindNodes = [];
for (let node of nodes) {
console.log("广度优先过程:" + node.value);
if(node.value === findValue){
return node;
}else{
nextFindNodes.push(node.left);
nextFindNodes.push(node.right);
}
}
return findNodeByScope(nextFindNodes, findValue);
}else{
return null;
}
}
console.log("find[广度优先]: 在tree中找出g元素", findNodeByScope([a], ' G'));