数据结构复习-二叉树

298 阅读3分钟

创建二叉树

let BiTree=function(ele){
    this.data=ele
    this.left=null
    this.right=null
}

遍历二叉树

二叉树有前中后以及层序遍历,最先想到的就是递归的方式来进行求解,那我们先来看看递归的方式如何求解

先序遍历(递归)

    function preorderTraversal(root){
        const res=[]
        if(!root) return null
        preorder(root,res)
        return res
    }
    function preorder(node,res){
        if(!node) return res
        res.push(node.val)
        preorder(node.left,res)
        preorder(node.right,res)
    }

递归其实比较简单,更加考察能力的是非递归,非递归的话我们得借助一个栈来存放暂时的节点

先序遍历(非递归)

    function preorderTraversal(root){
        const res=[],stack=[]
        if(!root) return res
        stack.push(root)
        while(stack.length){
            const node = stack.pop()
            res.push(node.val)
            if(node.right){stack.push(node.right)}
            if(node.left){stack.push(node.left)}
        }
        return res
    }

这个地方为什么先放node.right,因为借助的是一个栈,栈是先进后出,我们先序的顺序是根左右

后序遍历(递归)

    function postorderTraversal(root){
        const res=[]
        if(!root) return res
        postorder(root,res)
        return res
    }
    function postorder(node,res){
        if(!node) return res
        postorder(node.left,res)
        postorder(node.right,res)
        res.push(node.val)
    }

后序遍历(非递归)

先序遍历是根左右,后续遍历时左右根,那么我们可以在先序的基础上改一下,根左右先改成根右左,然后再反转,即得到所需的答案

    function postorderTraversal(root){
        const res=[],stack=[]
        if(!root) return res
        stack.push(root)
        while(stack.length){
            const node = stack.pop()
            res.push(node.val)
            //接下来是不同于先序的地方,我们要得到根右左,所以得先放左子树进栈
            if(node.left){stack.push(node.left)}
            if(node.right){stack.push(node.right)}
        }
        res.reverse()//将根右左翻转  得到左右根
        return res
    }

中序遍历(递归)

    function inorderTraversal(root){
        const res=[]
        if(!root) return res
        inorder(root,res)
        return res
    }
    function inorder(node,res){
        if(!node) return res
        inorder(node.left,res)
        res.push(node.val)
        inorder(node.right,res)
    }

中序遍历(非递归)

    function inorderTraversal(root){
        const res=[],stack=[]
        if(!root) return res
        let cur=root
        while(cur||stack.length){
            while(cur){
                stack.push(cur)
                cur=cur.left
            }
            const node = stack.pop()
            res.push(node.val)
            cur = node.right
        }
        return res
    }

层序遍历

    function levelOrderTraversal(root){
        const res=[],queue=[]
        if(!root) return res
        queue.push(root)
        while(queue.length){
            let curLevelSize = queue.length
            res.push([])
            for(let i=0;i<curLevelSize;i++){
                let node = queue.shift()
                res[res.length-1].push(node.val)
                if(node.left){queue.push(node.left)}
                if(node.right){queue.push(node.right)}
            }
        }
        return res
    }

二叉树相关题目

二叉镜像树

给定一个二叉树根节点root,输出其镜像二叉树

    function buildMirrorTree(root){
        if(!root) return root
        let left=builMirrorTree(root.left)
        let right=buildMirrorTree(root.right)
        root.left=right
        root.right=left
        return root
        
    }

对称二叉树

实现一个函数判断一个二叉树是否对称二叉树,如果一棵树二叉树和他的镜像是一样的,那么他是对称二叉树

    function isSymmetric(root){
        if(!root) return true
        return compare(root.left,root.right)
    }
    function compare(p,q){
        if(p==null&&q==null) return true
        else if(!p&&q) return false
        else if(p&&!q) return false
        return q.val==p.val&&compare(p.left,q.right)&&compare(p.right,q.left)
    }

平衡二叉树

平衡二叉树首先是二叉搜索树,即左子树的值小于根节点,右子树大于根节点,对其子树也是,而且左子树右子树的深度差不超过1,其子树也是平衡二叉树,为什么要有平衡二叉树,因为二叉搜索树可能退化成链表,降低查找效率,所以需要对其高度进行限制 实现一个函数,输入一个二叉树根节点,判断其是否为平衡二叉树

    function isBalanced(root){
        if(!root) return true
        return Math.abs(Depth(node.left)-Depth(node.right))<2&&isBalanced(root.left)&&isBalanced(root.right)
    }
    function Depth(node){
        if(!node) return 0
        return Math.max(Depth(node.left),Depth(node.right))+1
    }

二叉搜索树的第K大节点

通过中序遍历可以得到一个从小到大的排列,然后将其反序,即可通过索引得到

    function kthLargest(root,k){
        const res=[]
        inorderTraversal(root,res)
        return res[k-1]
    }
    function inorderTraversal(root,res){
        if(!root) return res
        const stack=[]
        let cur=root
        while(cur||stack.length){
            while(cur){
                stack.push(cur)
                cur=cur.left
            }
            const node = stack.pop()
            res.push(node.val)
            cur = node.right
        }
        return res
        
    }

二叉搜索树的最近公共祖先

二叉搜索树,又称二叉排序树,若左子树不为空,则左子树上所有节点均小于他的根节点,右子树不为空的化,右子树的所有节点均大于根节点

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

思路:如果两个节点相等返回任意一个,如果不等, 其中一个大于根节点其中一个小于节点返回根节点 如果都大于根节点,在右子树上找 如果都小于跟节点,在左子树上找

    function lowerstCommonAncestor(root,p,q){
        if(!root) return null
        if(p.val==q.val) return p
        while(root){
            if(p.val<root.val&&q.val<root.val){root=root.left}
            else if(p.val>root.val&&q.val>root.val){root=root.right}
            else{
                return root
            }
            
        }
        
    }

二叉树的公共祖先

这个不同于上一个题,因为上一个是搜索树,有序的,而这个是无序的

    function lowestCommonAncestor(root,p,q){
       if(root==null||p==root||q==root) return root
       let left = lowestCommonAncestor(root.left,p,q)
       let right = lowestCommonAncestort(root.right,p,q)
        if(left==null) return right
        if(right==null) return left
        return root
    }

重建二叉树

给定先序和中序遍历结果,根据遍历结果重建二叉树

    function buildTree(preorder,inorder){
        if(!preorder.length||!inorder.length) return null
        let rootval = preorder[0]
        let rootnode = new TreeNode(rootval)
        let index = inorder.indexOf(rootval)
        let left = buildTree(preorder.slice(1,index+1),inorder.slice(0,index))
        let right = buildTree(preorder.slice(index+1),inorder.slice(index+1))
        rootnode.left = left
        rootnode.right = right
        return rootnode
    }

相同的树

    function isSameTree(p,q){
        if(!q&&!p) return true
        if(!q&&p) return false
        if(q&&!p) return false
        return p.val==q.val&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right)
    }

树的子结构

输入两个二叉树A和B,判断B是不是A的子结构(约定空树不是任意一个树的子结构)

    function isSubStructure(A,B){
        if(A==null||B==null) return false
        return isSameTree(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B)
    }
    function isSameTree(node1,node2){
        if(node1==null&&node2==null) return true
        if(node1==null&&node2!=null) return false
        if(node1!=null&&node2==null) return false
        return node1.val==node2.val&&isSameTree(node1.left,node2.left)&&isSameTree(node1.right,node2.right)
    }

二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转成一个排序的循环双向链表,要求不能创建任何新节点,只能调整树中的指针的指向 思路:中序遍历

    function treeToDoubleList(root){
        if(!root) return null
        const stack=[]
        let pre=null
        let head=null
        let cur = root
        while(cur||stack.length){
            while(cur){
                stack.push(cur)
                cur=cur.left
            }
            const node = stack.pop()
            if(!pre){
                head=pre
            }
            else{
                pre.right= node
            }
            node.left = pre
            pre = node
            cur= node.right
        }
        head.left=pre
        pre.right=head
        return head
    }