其实这里写的也就是原代码,学数据结构很难,二叉树各种操作的核心,我目前领悟到的就是递归,递归,递归,学习要学习自己觉得很困难的知识,这样才会有进步。恩,这个鸡汤真馊!!
/**
*
* @param val
* @constructor
*/
function Node(val, left, right) {
this.val = val;
this.left = left;
this.right = right;
}
Node.prototype.show = function() {
return this.val;
}
/**
*
* @constructor
*/
function BTree() {
this.root = null;
this.depthBT = 0;
}
BTree.prototype = {
constructor : BTree,
add : function(val){
// 插入二叉树,找准规律,
// 1. 二叉树是值小的存放在左子树,值大的存放在右子树
// 2. 插入的时候,用根节点举例,是当一个节点的左子树或者右子树为空的时候才可以插入
// 3. 根据特点,可以得出大概思路,首先从根节点出发,判断是在根节点的左边还是右边,假设是在右边
// 4. 判断根节点的右子树是否为空,如果为空,则把当前值放入右子树
// 5. 如果不为空,则说明不能插入,需要把这个右子树设置为根节点,继续进行比较
var newNode = new Node(val, null, null);
if(!this.root) {
// 根节点初始化
this.root = newNode;
}else {
var current = this.root,
parent;// 保存current的值,表示父节点
while(current) {
parent = current;
if(val < current.val) {
// 判断是否是底层节点
current = current.left;
if(current == null ) {
parent.left = newNode;
return;
}
}else {
current = current.right;
if(current == null) {
parent.right = newNode;
return;
}
}
}
}
},
depth : function(node) {
// 求最大深度,是从最底层升序,即用递归,从顶层根节点向下延伸
// 到达最底层后,再次调用node.left和node.right,则都return 0
// 比较ldepth和rdepth,给最大的深度+1,这个1指的是这个子节点本身
// 向上回溯递归,其实就相当于是比较子节点的深度,然后把自己分配到子节点深度最深的节点链上
return !node ? 0 : Math.max(this.depth(node.left),this.depth(node.right)) + 1;
// if(!node) {
// return 0;
// }else {
// var ldepth = this.depth(node.left);
// var rdepth = this.depth(node.right);
// return ldepth > rdepth ? ldepth + 1 : rdepth + 1;
// }
},
preorder : function(node) {
// 举例:只有两层的二叉树23→16→45
// 传入跟节点,由于先序遍历,直接打印当前节点的node值(23)
// 传入左子树,作为新的node递归,先打印左子树的值(16),然后用左子树的.left递归,发现为空跳出
// 左子树的.right递归,发现为空跳出
// 传入右子树,作为新的node递归,先打印右子树的值(45),然后用右子树的.left递归,发现为空跳出
// 右子树的.right递归,发现为空跳出
// 先序遍历
if(node) {
console.log(node.show());
this.preorder(node.left);
this.preorder(node.right);
}
},
inorderTraversal : function(node) {
// 中序遍历
if(node){
this.inorderTraversal(node.left);
console.log(node.show());
this.inorderTraversal(node.right);
}
},
postorderTraversal : function(node) {
// 后序遍历
if(node) {
this.postorderTraversal(node.left);
this.postorderTraversal(node.right);
console.log(node.show());
}
},
BFS : function(node) {
// 1. 用数组模拟队列(先进先出),根节点入栈
// 2. 只要队列不为空,就打印出队列头
// 3. 判断节点左右子树是否各自为空,不为空则推入队列中
// 广度优先遍历
var nodes = [];
if(!node) {
console.log('empty tree');
}else {
nodes.push(node);
while(nodes.length !== 0) {
node = nodes.shift();// 队首出栈
console.log(node.val);
if(node.left) {
nodes.push(node.left);
}
if(node.right) {
nodes.push(node.right);
}
}
}
},
searchMin : function(node) {
// 最小值存储在左子树中,只需要一直访问左子树就可以了
// 查找最小值
while(node.left) {
node = node.left;
}
return node;
},
searchMax : function(node) {
// 查找最大值
while(node.right) {
node = node.right;
}
return node;
},
find : function(val) {
// 需要判断查找值和根节点值的大小,决定继续访问左子树还是右子树
// 查找指定值
var node = this.root,
parent = node;// 保存父节点
while(node) {
if(node.val === val) {
// 返回父节点对象和查找节点对象
return {nodeParent : parent,findNode : node};
}else{
parent = node;
if(node.val > val) {
node = node.left;
}else {
node = node.right;
}
}
}
return null;
},
removeNode : function(val) {
// 1.删除节点没有子树,为叶子结点,则把父元素指向他的指针置为null
// 2.删除节点有一个子树,则把父元素指向他的指针指向他的子树
// 3.删除节点有两个子树,(1)用左子树中的最小值代替删除节点并删除最小值节点 (2)用右子树中的最大值代替删除节点并删除最大值节点
// 删除节点
var currentobj = this.find(val),
parentNode,// 父元素
currentNode;// 查找元素
if(currentobj){
parentNode = currentobj.nodeParent;// 获得父元素
currentNode = currentobj.findNode;// 获得查找元素
if(currentNode.left == null && currentNode.right == null){
choosePos(null);
}else if(currentNode.left && currentNode.right){
var max = this.searchMax(currentNode.right).val,// 找到最大值节点
maxNode = this.find(max);// 找到最大值对象在二叉树中的父元素,以及本身
currentNode.val = max;// 将删除的节点的值改成最大值
maxNode.nodeParent.right = null;// 删除最大值节点,将最大值节点的父节点指向null
}else if(currentNode.right){// 右节点存在,左节点不存在
choosePos(currentNode.right);
}else if(currentNode.left) {// 左节点存在,右节点不存在
choosePos(currentNode.left);
}
}else{
return '删除节点不再树中';
}
// 只是为了获得一个操作句柄,但是不知道怎么处理,只能写了一个方法,很笨
function choosePos(setValue){
currentNode.val > parentNode.val ? parentNode.right = setValue : parentNode.left = setValue;
}
}
}
var bt = new BTree(),
arrTree = [23,45,16,37,3,4,99,22,44,52,42,10,100,1];
arrTree.forEach(function(i){
// 生成二叉树
bt.add(i);
});
console.log(bt);
console.log('先序');
bt.preorder(bt.root);
console.log('中序');
bt.inorderTraversal(bt.root);
console.log('后序');
bt.postorderTraversal(bt.root);
// 二叉树深度
console.log(bt.depth(bt.root));
// 查找二叉树最小值
console.log('查找最小值 ' + bt.searchMin(bt.root).val);
// 查找二叉树最大值
console.log('查找最大值 ' + bt.searchMax(bt.root).val);
// 查找指定值
console.log('查找结果父元素的值:' + bt.find(99).nodeParent.val);
console.log('查找结果的值:' + bt.find(99).findNode.val);
// 删除节点
console.log('删除节点之前查找结果父元素:' + bt.find(52).nodeParent.val);
bt.removeNode(52);
console.log('删除节点之后查找结果:' + bt.find(52));
console.log(bt.removeNode(55));