求一棵树的镜像(普通模式)
对于一棵树,如果每个节点的左右子树互换位置,那么就变成了这棵树的镜像
请实现mirror方法
每个节点的左右子树都要互换位置,树的许多方法,使用递归实现都非常方便,其原理在于,每一个节点和它的子孙节点在局部都构成一棵新的树。树的镜像,就是把每一个节点的左右子树互换位子,这和我们在数组中交换两个元素的位置是相似的操作
var bt = new BinaryTree();
bt.init_tree("A(B(D,E(G,)),C(,F))#");
var root_node = bt.get_root();
var mirror_1 = function(node){
if(!node){
return;
}
// 用tmp保存右孩子
var tmp = node.leftChild;
// 左孩子等于右孩子
node.leftChild = node.rightChild;
// 右孩子等于左孩子
node.rightChild = tmp;
// 继续翻转
mirror_1(node.leftChild);
mirror_1(node.rightChild);
}
var mirror_2 = function(node){
if(!node){
return null;
}
// 翻转左子树
var left = mirror_2(node.leftChild);
// 翻转右子树
var right = mirror_2(node.rightChild);
// 左右孩子互换
node.rightChild = left;
node.leftChild = right;
// 返回当前节点
return node;
};
mirror_2(root_node);
bt.in_order(root_node);
使用非递归方式实现前序遍历
请实现非递归的pre_order方法,程序输出结果为 A B D E G C F
递归转为非递归,要使用while循环。
前序遍历,先处理当前节点,curr_node,然后处理curr_node.leftChild,最后处理curr_node.rightChild,那么在while循环里,让curr_node=curr_node.leftChild,就可以实现对左子树访问处理,但问题在于访问处理左子树结束之后,要找到对应右子树,因此需要一个数据结构,能够在左子树访问结束后返回这棵左子树对应的右子树,前面学过的栈,恰好可以实现这样的功能
以上面的图为例,逻辑推理如下
最初curr_node = 1
-
处理curr_node(此时为1), 3入栈,curr_node = curr_node.leftChild
-
处理curr_node(此时为2),5入栈, curr_node = curr_node.leftChild
-
处理curr_node(此时为4),处理结束后,不能继续访问左子树,执行pop,curr_node = 5
-
处理curr_node(此时为5),处理结束后,不能继续访问左子树,执行pop,curr_node = 3
-
处理curr_node(此时为3),7入栈,curr_node = curr_node.leftChild
-
处理curr_node(此时为6),访问结束后,不能继续访问左子树,执行pop,curr_node = 7
-
处理curr_node(此时为7),访问结束后,pop,栈里已经没有元素了,无法继续处理
var bt = new BinaryTree(); bt.init_tree("A(B(D,E(G,)),C(,F))#"); var root_node = bt.get_root();
function pre_order(node){ var stack = new Stack(); var curr_node = node;
while(curr_node){ console.log(curr_node.data); if(curr_node.rightChild){ stack.push(curr_node.rightChild); } if(curr_node.leftChild){ curr_node = curr_node.leftChild; }else{ curr_node = stack.pop(); } }};
pre_order(root_node);
使用非递归方式实现中,后两种遍历方法
const BinaryTree = require('./binarytree')
const Stack = require('./stack');
var bt = new BinaryTree.BinaryTree();
bt.init_tree("A(B(D,E(G,)),C(,F))#");
var root_node = bt.get_root();
function in_order(node){
var stack = new Stack.Stack();
var curr_node = node;
while(true){
// 先要处理左子树,当前节点怎么办? 放到栈里,等左子树处理完了弹出栈顶
while(curr_node){
stack.push(curr_node);
curr_node = curr_node.leftChild;
}
// 处理栈顶
var pop_item = stack.pop();
console.log(pop_item.data);
// 处理右子树,如果右子树是null,下一次循环,恰好可以跳过while(curr_node) 的这个循环
curr_node = pop_item.rightChild;
if(!curr_node && stack.isEmpty()){
break;
}
}
};
bt.in_order(root_node);
in_order(root_node);
非递归后序遍历
const BinaryTree = require('./binarytree')
const Stack = require('./stack');
var bt = new BinaryTree.BinaryTree();
bt.init_tree("A(B(D,E(G,)),C(,F))#");
var root_node = bt.get_root();
var Tag = function(node, state){
this.node = node;
this.state = state; // 0表示左边已经遍历结束,1表示右边已经遍历结束
};
function post_order(node){
var stack = new Stack.Stack();
var curr_node = node;
while(true){
while(curr_node){
var tag = new Tag(curr_node, 0);
stack.push(tag);
curr_node = curr_node.leftChild;
}
var pop_item = stack.pop();
if(pop_item.node.rightChild && pop_item.state==0){
pop_item.state = 1;
stack.push(pop_item);
curr_node = pop_item.node.rightChild;
}else{
console.log(pop_item.node.data);
}
if(!curr_node && stack.isEmpty()){
break;
}
}
};
post_order(root_node);
寻找两个节点的最近公共祖先
var bt = new BinaryTree();
bt.init_tree("A(B(D,E(G,)),C(,F))#");
var root_node = bt.get_root();
var node1 = bt.find("D");
var node2 = bt.find("G");
console.log(node1.data);
console.log(node2.data);
// 寻找最近公共祖先
var lowest_common_ancestor = function(root_node, node1, node2){
// 实现你的算法
};
var ancestor = lowest_common_ancestor(root_node, node1, node2);
console.log(ancestor.data);
示例代码
const BinaryTree = require('./binarytree');
var bt = new BinaryTree.BinaryTree();
bt.init_tree("A(B(D,E(G,)),C(,F))#");
var root_node = bt.get_root();
var node1 = bt.find("D");
var node2 = bt.find("G");
// 寻找最近公共祖先
var lowest_common_ancestor = function(root_node, node1, node2){
if(!root_node || root_node==node1 || root_node==node2){
return root_node;
}
var left = lowest_common_ancestor(root_node.leftChild, node1, node2);
var right = lowest_common_ancestor(root_node.rightChild, node1, node2);
if(left && right){
return root_node;
}
if(left){
return left;
}
return right;
};
var ancestor = lowest_common_ancestor(root_node, node1, node2);
console.log(ancestor.data);
分层打印二叉树
// 层次遍历
var level_order = function(node){
var queue = new Queue.Queue();
// 把当前节点放入到队列
queue.enqueue(node);
queue.enqueue(0);
var str_link = "";
while(!queue.isEmpty()){
del_item = queue.dequeue();
if(del_item == 0){
console.log(str_link);
str_link = "";
if(queue.isEmpty()){
break;
}else{
queue.enqueue(0);
}
continue;
}
str_link += del_item.data + " ";
// 把左右子节点放入到队列
if(del_item.leftChild){
queue.enqueue(del_item.leftChild);
}
if(del_item.rightChild){
queue.enqueue(del_item.rightChild);
}
}
};
level_order(root_node);
输出指定层的节点个数
实现函数get_width 返回第n层的节点个数
// 获得宽度
var get_width = function(node, n){
if(node == null){
return 0
}
var queue = new Queue.Queue();
// 把当前节点放入到队列
queue.enqueue(node);
queue.enqueue(0);
var width = 1;
var level = 0;
while(!queue.isEmpty()){
del_item = queue.dequeue();
if(del_item == 0){
level += 1;
if(level == n){
return width;
}
width = queue.size();
if(queue.isEmpty()){
break;
}else{
queue.enqueue(0);
}
}
// 把左右子节点放入到队列
if(del_item.leftChild){
queue.enqueue(del_item.leftChild);
}
if(del_item.rightChild){
queue.enqueue(del_item.rightChild);
}
}
};
console.log(get_width(root_node, 1));
console.log(get_width(root_node, 2));
console.log(get_width(root_node, 3));
console.log(get_width(root_node, 4));