数据结构之----树2

151 阅读4分钟

求一棵树的镜像(普通模式)

对于一棵树,如果每个节点的左右子树互换位置,那么就变成了这棵树的镜像
请实现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

  1. 处理curr_node(此时为1), 3入栈,curr_node = curr_node.leftChild

  2. 处理curr_node(此时为2),5入栈, curr_node = curr_node.leftChild

  3. 处理curr_node(此时为4),处理结束后,不能继续访问左子树,执行pop,curr_node = 5

  4. 处理curr_node(此时为5),处理结束后,不能继续访问左子树,执行pop,curr_node = 3

  5. 处理curr_node(此时为3),7入栈,curr_node = curr_node.leftChild

  6. 处理curr_node(此时为6),访问结束后,不能继续访问左子树,执行pop,curr_node = 7

  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));