基本结构
创建 插入 删除 查找 遍历 深度
// 二叉树有一个特殊性:相对本节点较小的值保存在左节点,相对本节点较大的值保存在右节点,该特性能让查值效率提高
//创建结点
function Node(data, left, right) {
this.data = data;
this.left = left;
this.right = right;
}
//展示结点数据
Node.prototype = {
show: function () {
console.log(this.data);
}
}
//树构造函数
function Tree() {
this.root = null;
}
Tree.prototype = {
//插入
// 二叉树有一个<b>特殊性:相对本节点较小的值保存在左节点,
//相对本节点较大的值保存在右节点</b>,该特性能让查值效率提高
insert: function (data) {
var node = new Node(data, null, null);
if(!this.root) {
this.root = node;
return;
}
var current = this.root;
var parent = null;
while (current) {
parent = current;
if (data < parent.data) {
current = current.left;
if(!current) {
parent.left = node;
return;
}
} else {
current = current.right;
if(!current) {
parent.right = node;
return;
}
}
}
},
//删除操作稍微复杂一些。思路在于首先找到删除值的结点,若该结点是叶子结点,则直接将其置为null,
//若其具有左子树或右子树,则将左孩子结点或右孩子结点赋值给当前结点。
//若当前结点既有左子树,又有右子树,则在其左子树中,寻找一个和当前结点值最接近的孩子结点(即中序遍历结果中当前结点的前驱),
//将当前结点的值替换为该孩子结点的值,替换后,树中此时就有两个重复的值,因此,再利用递归删除重复的孩子结点,依次类推。。。
// 从待删除节点的左子树找节点值最大的节点A,替换待删除节点,并删除节点A;
// 从待删除节点的右子树找节点值最小的节点A,替换待删除节点,并删除节点A。
// 为什么要找右子树最小值(或者左子树的最大值)呢?因为右子树最小值比左子树的所有值都大,却比右子树的所有值小,这正是根节点的特性,用它来替代根节点再适合不过了。
delete: function(root, data) {
if(!root) {
console.log("删除失败")
return root;
}
if(data < root.data) {//若当前结点值大于删除值,则继续在左子树中寻找删除值
root.left = this.delete(root.left, data)
} else if (data > root.data) {//若当前结点值小于删除值,则继续在右子树中寻找删除值
root.right = this.delete(root.right, data)
} else {找到与删除中相等的结点
if(root.left === null && root .right === null) {//叶子结点
root = null;
} else if(root.left === null) {//只有右子树
root = root.right
} else if(root.right === null) {//只有左子树
root = root.left
} else {//同时具有左右子树
let prevNode = root.left;
while(prevNode.right) {//寻找不大于当前结点值的最大结点值
prevNode = prevNode.right
}
root.data = prevNode.data //替换值
root.left = this.delete(root.left, prevNode.data);//递归左子树,删除重复值的结点
}
}
return root
},
//前序遍历
preOrder: function (node) {
if (node) {
node.show();
this.preOrder(node.left);
this.preOrder(node.right);
}
},
//中序遍历
middleOrder: function (node) {
if (node) {
this.middleOrder(node.left);
node.show();
this.middleOrder(node.right);
}
},
//后序遍历
laterOrder: function (node) {
if(node) {
this.laterOrder(node.left);
this.laterOrder(node.right);
node.show();
}
},
//获取最小值
getMin: function () {
var current = this.root;
while(current) {
if(!current.left) {
return current
}
current = current.left;
}
},
//获取最大值
getMax: function () {
var current = this.root;
while(current) {
if(!current.right) {
return current;
}
current = current.right;
}
},
//获取深度
getDeep: function (node, deep) {
deep = deep || 0;
if(node == null) {
return deep;
}
deep++;
var dleft = this.getDeep(node.left, deep);
var dright = this.getDeep(node.right, deep);
return Math.max(dleft, dright);
},
//查找结点
getNode: function (data, node) {
if(node) {
if(node) {
if(data === node.data) {
return node;
} else if (data < node.data) {
return this.getNode(data, node.left);
} else {
return this.getNode(data, node.right);
}
}
} else {
return null
}
}
}
var t = new Tree();
t.insert(3);
t.insert(9);
t.insert(1);
t.insert(8);
t.insert(2);
t.insert(7);
t.insert(4);
t.insert(5);
t.insert(0);
console.log(t);
t.middleOrder(t.root);
console.log("MIN/n", t.getMin(), "MAX/n", t.getMax(), "DEEP", t.getDeep(t.root, 0), "getNode", t.getNode(5,t.root))