二叉搜索树--中序、前序、后序遍历 --JavaScript

1.二叉树

最多只有两个节点的树

2.二叉搜索树

是二叉树的一种,但是只允许它的左子树小于父节点,右子树大于或等于父节点

3.先序遍历,先访问根节点==》左节点==》右节点

4.中序遍历,左节点===》根节点==》右节点

5.后序遍历,左节点==》右节点==》根节点

代码实现:

var BinaryTree = function () {
    var Node = function (val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
    var root = null;

    //向树中插入一个新的节点
    var insertNode = function (node,newnode) {
       if(newnode.val < node.val){
           if(node.left === null){
               node.left = newnode;
           }else{
               insertNode(node.left,newnode)
           }
       }else {
           if(node.right === null){
               node.right = newnode;
           }else{
               insertNode(node.right,newnode);
           }
       }
    }
    this.insert = function (val) {
        var node = new Node(val);
        if(root === null){
            root = node;
        }else{
            insertNode(root,node);
        }
    }
    //查找一个值,存在返回true,不存在返回false
    var searchTree1 = function (node,val) {
        if(node === null){
            return false;
        }
        if(node.val >val){
            return searchTree1(node.left,val);
        }else if(node.val<val){
           return searchTree1(node.right,val);
        }else {
            return true;
        }

    }
    this.serach = function (val) {
        return searchTree1(root,val);
    }
    //递归方法,中序遍历所有节点
    var inorder = function (node,cb) {
        if(node !== null) {
            inorder(node.left,cb);
            cb(node.val);
            inorder(node.right,cb);
        }

    }
    this.inOrderTraverse = function (cb) {
        inorder(root,cb);
    }
    //递归,前序遍历所有节点
    var preorder = function (node,cb) {
        if(node !== null){
            cb(node.val);
            preorder(node.left,cb);
            preorder(node.right,cb);
        }

    }
    this.preOrderTraverse = function (cb) {
        preorder(root,cb)
    }

    //递归,后序遍历所有节点
    var postorder = function (node,cb) {
        if(node !== null) {
            postorder(node.left,cb);
            postorder(node.right,cb);
            cb(node.val);
        }
    }
    this.postOrderTraverse = function (cb) {
        postorder(root,cb)
    }

    //最小值
    var minval = function (node) {
        if(node === null){
            return null;
        }
        while(node!=null&&node.left!=null){
            node = node.left;
        }
        return node.val;
    }
    this.min = function () {
        return minval(root);
    }
    //最大值
    var maxval = function (node) {
        if(node === null){
            return null;
        }
        while(node!=null&&node.right!=null){
            node = node.right;
        }
        return node.val;
    }
    this.max = function () {
        return maxval(root);
    }
    //删除某个节点
    var anxNode = function (node) {
        while(node!==null&&node.left!==null){
            node = node.left;
        }
        return node;
    }
    var removeNode = function (node,val) {
        if(node === null){
            return false;
        }
        if(node.val === val){
            //1左右节点都为空的情况
            if(node.left === null&&node.right===null){
                node = null;
                return node;
            }
            //2.左节点不为空,右节点为空的情况
            else if(node.left!==null&&node.right===null){
                node = node.left;
                return node;
            }
            //3.左节点为空,右节点不为空
            else if(node.left === null &&node.right!==null){
                node = node.right;
                return node;
            }
            //左右节点都不为空,此时应该找右节点的最小左节点作为替换删除节点的节点
            else if(node.left!==null&&node.right!==null){
                var anx = anxNode(node.right);
                node.val = anx.val;
                node.right = removeNode(node.right,node.val);
                return node;
            }
        }else if(node.val < val){
            node.right = removeNode(node.right,val);
            return node;
        }else{
            node.left = removeNode(node.left,val);
            return node;
        }
    }
    this.remove = function (val) {
        removeNode(root,val);
    }
    this.getRoot = function () {
        return root;
    }
}

6先序遍历首先初始化一个栈,将根节点压入栈,1.当栈不为空的时候取出栈顶元素node1,访问,并存入数组2.如果node1的右节点不为空,将node1的右节点压入栈 3.如果node1的左节点不为空将它压入栈 当栈不为空时,循环1,2,3 注意应该先让右节点先入栈代码实现:

var preOrder = function (node,cb) {
    var res = [];
    var stack = [];
    stack.push(node);
    while (stack.length){
        var node1 = stack.pop();
        res.push(node1.val);
        cb(node1.val);
        if(node1.right!==null){
            stack.push(node1.right);
        }
        if(node1.left!==null){
            stack.push(node1.left);
        }
    }
    return res;
}

7中序遍历,非递归思路: 将当前节点压入栈,然后将左子树当作当前节点,如果当前节点为空,将双亲节点取出来,访问该节点 并将该节点存入数组,然后将右节点当作当前节点,进行循环

var inOder = function (node,cb) {
    let result = [];
    let stack = [];
    while(stack.length || node) { // 是 || 不是 &&
        if(node) {
            stack.push(node);
            node = node.left;
        } else {
            node = stack.pop();
            result.push(node.value);
            cb(node.val);
            node = node.right; // 如果没有右子树 会再次向栈中取一个结点即双亲结点
        }
    }
    return result;
}
 

8.后序遍历的非递归算法实现
思路:

首先将根节点压入栈, 当栈不为空时执行以下循环:

如果当前节点有左子树存在且没有被访问过!touch,将touch修改为‘left'表示已经访问过了并将该节点压入栈,并令当前节点为该节点的左节点,

如果当前节点的右子树存在并且touch !=='right' 表示没有被访问过,将该节点touch赋值为'right',  将该节点压入栈,令当前节点等于他的右节点 

如果当前节点左右子树都不存在,那么获取栈顶元素,删除touch属性,并将值保存在数组中, *然后在令当前节点为栈顶元素继续回溯,直到栈为空

代码:

var postOrder = function (node,cb) {
    var stack = [];
    var res = [];
    stack.push(node);
    while(stack.length){
        if(node.left && !node.touch){
            node.touch = 'left';
            node = node.left;
            stack.push(node);
            continue;
        }
        if(node.right && node.touch !== 'right'){
            node.touch = 'right';
            node = node.right;
            stack.push(node);
            continue;
        }
        //当node的左右节点都为空的时候,获取栈顶元素,并且访问它
        node = stack.pop();
        node.touch && delete node.touch;//如果node有touch属性就删除这个属性
        res.push(node.val);
        cb(node.val);
        node = stack.length?stack[stack.length-1]:null;
    }
    return res;
}

9.广度遍历(层次遍历)

主要利用队列实现的,广度遍历是从二叉树的根结点开始,自上而下逐层遍历;在同一层中,按照从左到右的顺序对结点逐一访问。

递归算法:

var bfsDigui = function (node) {
            var stack = [];
            var res = [];
            var count = 0;
            stack.push(node);
            function f() {
                var newnode = stack[count];
                if(newnode){
                    res.push(newnode.val);
                    newnode.left && stack.push(newnode.left);
                    newnode.right && stack.push(newnode.right);
                    count++;
                    f();
                }
            }
            f();
            return res;
        }

非递归算法,没有使用shift()方法,因为比较消耗性能:

var bfs = function (node) {
            var stack = [];
            var res = [];
            var pointer = 0;
            stack.push(node);
            while(pointer<stack.length){
                var node = stack[pointer];
                res.push(node.val);
                node.left && stack.push(node.left);
                node.right &&stack.push(node.right);
                pointer++;
            }
            return res;
        }
        this.bfs2 = function () {
            return bfs(root);
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值