搜索二叉树

二叉树的基本问题:
二叉树是递归定义的,因此相关问题基本都可以用递归实现。递归在本质上就是一个栈。

二叉搜索树:对于树中的每个节点X,它的左子树中所有项的值都小于X,右子树所有值都大于X。

定义一个二叉树:

private class BSTNode<T>{

        T key;
        BSTNode<T> left;
        BSTNode<T> right;

        //constructors
        public BSTNode(T key){
            this(key,null,null);
        }

        public BSTNode(T key,BSTNode<T> left,BSTNode<T> right){

            this.key= key;
            this.left=left;
            this.right=right;
        }

    }

基本方法:查找 search ,发现最大最小值,插入,打印,遍历

public class BSearchTree <T extends Comparable>{


    private class BSTNode<T>{

        T key;
        BSTNode<T> left;
        BSTNode<T> right;

        //constructors
        public BSTNode(T key){
            this(key,null,null);
        }

        public BSTNode(T key,BSTNode<T> left,BSTNode<T> right){

            this.key= key;
            this.left=left;
            this.right=right;
        }

    }

    private BSTNode<T>  mRoot;//根结点

    /*
     * 前序遍历   ----递归-----
     * */
    public void preOrder(){
        if(isEmpty()){
            System.out.println("Empty tree");
        }else{
        preOrder(mRoot);}
    }

    private void preOrder(BSTNode<T> tree){
        if(tree!=null){
            System.out.print(tree.key+" ");
            preOrder(tree.left);
            preOrder(tree.right);

        }
    }

    /*
     * 中序,后序遍历递归 类似。
     * */

    /*
     * http://www.gocalf.com/blog/traversing-binary-tree.html#id9
     * 前序和中序:  ---非递归---
     * (非递归方式使用的栈(数据结构))
     * 需要自己维护一个栈来保存需要但尚未来得及处理的数据。
     * 
     * */
    public  void interativePreOrder(String Order){
        interativePreOrder(mRoot,Order);
    }

    private void interativePreOrder(BSTNode<T> tree,String Order){
        Stack<BSTNode<T>> stack = new Stack<BSTNode<T>>();
        //这里不可以写成 stack!=null
        while(tree!=null||stack.size()>0){
            while(tree!=null){
            if(Order=="NLR"){
                   System.out.print(tree.key+" ");}
            stack.push(tree);
            tree=tree.left;

            }
            if(stack.size()>0){

                tree = stack.pop();
                if(Order=="RLR"){
                    System.out.print(tree.key+" ");
                }
                tree=tree.right;

            }

        }

    }

    /*
     * 后序遍历:  ---非递归--
     * 下面
     * */

    /*
     * 查找   ---递归---
     * */
    public BSTNode<T> search(T key){
        return search(mRoot,key);

    }

    private BSTNode<T> search(BSTNode<T> x,T key){
        if(x==null)
            return x;

        int cmp=key.compareTo(x.key);
        if(cmp<0){
            return search(x.left,key);
        }else if(cmp>0){
            return search(x.right,key);
        }else 
            return x;

    }

    /*
     * 查找  ---非递归---
     * */

    public BSTNode<T> iterativeSearch(T key){

        return iterativeSearch(mRoot,key);
    }

    private BSTNode<T> iterativeSearch(BSTNode<T> x,T key){

        while(x!=null){
            int cmp = key.compareTo(x.key);

            if(cmp < 0)
                x=x.left;
            else if(cmp > 0)
                x=x.right;
            else return x;  

        }
        return x;
    }   

    /*
     * 查找最小节点:返回tree 为根节点的二叉树最小节点
     * */
    public T  findMin(){
        return findMin(mRoot).key;
    }

    private BSTNode<T> findMin(BSTNode<T> x){

        if(x==null)
            return null;

        while (x.left!=null){
            x=x.left;
        }
        return x;
    }

    /*
     * 查找最大节点   ---递归方法----
     * */
    public T findMax(){
        return findMax(mRoot).key;
    }

    private BSTNode<T> findMax(BSTNode<T> x){
        if(x==null)
            return null;
        else if(x.right==null)
            return x;
        //递归实现
        return findMax(x.right);

    }

    /*
     * 插入方法 insert  ----递归---
     * */
    public void insert(T x){
        BSTNode<T> newNode = new BSTNode<T>(x,null,null);
        //mRoot=insert(newNode,mRoot);
        mRoot=insert(newNode,mRoot);
    }

    /*
     * a.若当前的二叉查找树为空,则插入的元素为根节点 
     * b.若插入的元素值小于根节点值,则将元素插入到左子树中
     * c.若插入的元素值不小于根节点值,则将元素插入到右子树中。
     *   首先找到插入的位置,要么向左,要么向右,直到找到空结点,即为插入位置,
     *   如果找到了相同值的结点,插入失败
     * */

     private BSTNode<T> insert(BSTNode<T> newNode,BSTNode<T> root){
         /*
             * 比如遍历到某个节点的右节点为空,
             * 则让 newNode 为这个节点的根节点,即插入了该点
             * */
         if(root==null)         
             root=newNode;

         int cmp = newNode.key.compareTo(root.key);
         if(cmp < 0)
             //忘记加 root.left,创建的是空树??是不是root就是子节点了,而不是最初的根节点了
            // return insert(newNode,root.left);
             //忘记加root.left 无法在root与left之间建立关系。所以最后就只有一个根
          root.left=insert(newNode,root.left);
         else if(cmp > 0)
             //return insert(newNode,root.right);
         root.right= insert(newNode,root.right);
         else 
             ;//重复节点,什么也不做

         return root;        

     }

    public boolean isEmpty(){
        return mRoot==null;
    }
    /*
     * 打印二叉树
     * */
    public void print(){
        if(mRoot!=null){
            print(mRoot,mRoot.key,0);
        }

    }

    private void print(BSTNode<T> tree, T key, int direction){
        if(tree!=null){
            if(direction==0)//tree是根节点
                 System.out.println(tree.key+" is root;");
            else if(direction==1)
                 System.out.print(tree.key+" is "+key + " right;");
            else System.out.print(tree.key+" is "+key+" left;");
            print(tree.left,tree.key,-1);
            print(tree.right,tree.key,1);

        }
    }

   public static void main(String[] args) {
        int []arr={1,5,4,3,2,6};

        BSearchTree<Integer> tree= new BSearchTree<Integer>();
        System.out.println("依次添加");

        int n=arr.length;
        for(int i=0;i<n;i++){
            //System.out.print(arr[i]+" ");
            tree.insert(arr[i]);
        }
        //tree.preOrder();
        System.out.println("\n===print");
        tree.print();
        System.out.println("\n===findmin "+tree.findMin());
        System.out.println("===findmax "+tree.findMax());
        System.out.println("===search 5 :"+tree.search(5).key);

        System.out.println("===插入9");
        tree.insert(9);
        System.out.println("===递归前序遍历");
        tree.preOrder();
        System.out.println("\n 非递归前序");
        tree.interativePreOrder("NLR");
        System.out.println("\n非递归中序");
        tree.interativePreOrder("RLR");
        System.out.println("\n非递归后序");
        tree.iterativePostorder();
        }

面试中二叉树的相关问题:
二叉树深度,分层遍历,转化为双向列表,结点个数,K 层节点,叶结点个数,两棵树是否相同,是否是平衡二叉树,根据遍历结果,重建二叉树,A是否是B的子树

/*
     *一, 二叉树深度(递归)
     * 1) 如果二叉树为空,节点个数为0;
     * 2)不为空,深度=max(左子树深度,右子树深度)
     * */

    public int GetDep(){

        return GetDep(mRoot);
    }

    private int GetDep(BSTNode <T> tree){

        if(tree==null)
            return 0;
        //每个子节点又作为根节点,判断一次左右节点深度。
        int leftDep=GetDep(tree.left);
        int rightDep=GetDep(tree.right);
        //返回左右子树深度的最大值
        return (leftDep > rightDep)?(leftDep+1):(rightDep+1);
    }



    /*
     * 二, 分层遍历(按层次从上向下,从左向右)
     * 广度搜索(前序遍历等是深度搜索)
     * 假设这树的结构如下:
     *                8
     *          6           10
     *      5       7    9      11
     *那么先是打印出8,然后将它的子结点6和10保存起来,然后打印6,保存它的两个子结点5和7,接着打印10...
     *到了这里,可以察觉到,比起5和7,10先存放起来,然后又先打印出来,说明这是一个"先进先出"的结构,
     *也就是所谓的队列。
     * */

    public void LevelTraverse(){
        LevelTraverse(mRoot);
    }
    /*
     * 先将树的根节点入队,
     *  如果队列不空,则进入循环:
     *  将队首元素出队,并输出; 若有左孩,则左孩入队;若有右孩,则右孩入队
     * */
    private void LevelTraverse(BSTNode<T> tree){

        if(tree==null)
            return;//这里为什么是return???是跳出这个函数?
        LinkedList<BSTNode<T>> queue= new LinkedList<BSTNode<T>>();

        queue.addLast(tree);

        while(!queue.isEmpty()){
            /*
             * public E pop() {
             *    return removeFirst();
             *     }
             * */
            BSTNode<T> cur=queue.removeFirst();     

            System.out.print(cur.key+" ");

            /*
             *  public void push(E e) {
             *       addFirst(e);
             *     }
             * */           
            if(cur.left!=null)
                queue.addLast(cur.left);
            if(cur.right!=null)
                queue.addLast(cur.right);

        }

    }

    /*
     * 三, 二叉树转化为有序的双向列表(递归方法)
     * 因为是有序列表,搜索二叉树的特点可知,中序遍历是按照顺序来的
     * 
     *  二叉树中的左结点总是比根结点小,而右结点又比根结点大,在双向链表中,
     *  每个结点都有两个指针,一个指向前面的结点,另一个指向后面的结点。
     *  根据这样的特性,二叉树的确可以转换成排序的双向链表。
     * */
    public BSTNode<T> convertBtoDLL (){
        mRoot = convertBtoDLL(mRoot);

        //root 会在链表的中间位置,因此需要手动把 root 移动到链表头??
        while(mRoot.left!=null){
            mRoot=mRoot.left;
        }
        return mRoot;
    }

    //递归转换BST 为DLL
    private BSTNode<T> convertBtoDLL(BSTNode<T> root){
        if(root==null||(root.left==null&&root.right==null)){
            return root;

        }

        BSTNode<T> tmp=null;//是什么?

        //处理左子树     
        if(root.left!=null){
            tmp=convertBtoDLL(root.left);
            //寻找最右节点
            while(tmp.right!=null){
                tmp=tmp.right;
            }
            //左子树处理后的结果和root 相连
            tmp.right=root;
            root.left=tmp;
        }

        //处理右子树
        if(root.right!=null){
            tmp = convertBtoDLL(root.right);
            //寻找最左节点
            while(tmp.left!=null){
                tmp=tmp.left;
            }
            tmp.left=root;
            root.right=tmp;
        }
        return root;
    }
    //输出DLL
    public void printDll(BSTNode<T> root){

        while(root!=null){
            System.out.print(root.key+" ");
            root=root.right;
        }
    }
    /* 
     * 四,求二叉树结点个数  ----递归---
     * */
    public int GetNum(){
        return GetNum(mRoot);
    }

    private int GetNum(BSTNode<T> tree){
        if(tree==null)
            return 0;
        //进入某个左节点,以他为根,继续计算左右节点个数
        return GetNum(tree.left)+GetNum(tree.right)+1;

    }
    /*
     * 二叉树节点个数    ----非递归---
     * 同分层遍历类似
     * */
    public  int GetNum1(){
        return GetNum1(mRoot);
    }
    private int GetNum1(BSTNode<T>  root){
        if(root==null)
            return 0;

        int count=0;
        LinkedList<BSTNode<T>> queue=new LinkedList<BSTNode<T>>();
        queue.addFirst(root);

        while(queue.size()>0){
            BSTNode<T> cur=queue.removeLast();

            if(cur.left!=null){
                queue.addLast(cur.left);
                count++;
            }

            if(cur.right!=null){
                queue.addLast(cur.right);
                count++;
            }

        }
        return count+1;
    }


 /* 
   * 五,求二叉树第K层的节点个数     ---递归--- 
   *  
   * (1)如果二叉树为空或者k<1返回0 
   * (2)如果二叉树不为空并且k==1,返回1 
   * (3)如果二叉树不为空且k>1,返回root左子树中k-1层的节点个数与root右子树k-1层节点个数之和 
   *  
   * 求以root为根的k层节点数目 等价于 求以root左孩子为根的k-1层(因为少了root那一层)节点数目 加上 
   * 以root右孩子为根的k-1层(因为少了root那一层)节点数目 
   *  
   *  
  */

    public int getKnum(int k){
        return getKnum(mRoot,k);

    }

    private int getKnum(BSTNode<T> root,int k){
        if(k<1||root==null)
            return 0;
        else if (k==1)
            return 1;
        int leftNum=getKnum(root.left,k-1);
        int rightNum=getKnum(root.right,k-1);

        return (leftNum+rightNum);

    }

    /*
     *六, 二叉树中叶子节点的个数   ----递归----
     * 注意与求 节点个数 的不同
     *    
     *(1)如果二叉树为空,返回0
     *(2)如果二叉树不为空且左右子树为空,返回1
     *(3)如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数
     * */

    public int getLeafNum(){
        return getLeafNum(mRoot);
    }
    private int getLeafNum(BSTNode<T> tree){

        //root 不存在,返回0
        if(tree==null)
            return 0;

        //root左右子树都为空,是叶节点,返回1
        if(tree.left==null&&tree.right==null)
            return 1;

        int lef=getLeafNum(tree.left);
        int rig=getLeafNum(tree.right);

        return lef+rig; 
    }
    /*求叶子节点个数   ----非递归---
     * 类似于层序遍历,每一层没有子节点的就是叶节点,leafCount ++
     * */
    public int getLeafNum1(){
        return getLeafNum(mRoot);
    }
    private int getLeafNum1(BSTNode<T> tree){
        //不能忘记初始判断 是否为空
        if(tree==null)
            return 0;

        int leafCount=0;//叶节点计数
        LinkedList<BSTNode<T>> queue=new LinkedList<BSTNode<T>>();
        queue.add(tree);
        /*
         * 将根节点放入队列,从开始取出,判断它是否有左右节点,没有,则是叶节点,
         * 有的话,就将其左右节点推入队列中(此时队列中的是该节点同层的右侧,下一层该节点子节点前面的部分),
         * 等待读取。
         * */
        while(queue.size()>0){
            tree = queue.removeLast();

            if(tree.left!=null)
                queue.add(tree.left);
            if(tree.right!=null)
                queue.add(tree.right);
            if(tree.left==null&&tree.right==null)
                leafCount++;
        }
        return leafCount;

    }

    /*
     * 七,判断两个树是否是同一个树    ---递归---
     * (1)如果两棵二叉树都为空,返回真 
     * (2)如果两棵二叉树一棵为空,另一棵不为空,返回假  
     * (3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假 
     * */


    public  boolean isSame(BSTNode<T> tree1,BSTNode<T> tree2){
        if(tree1==null&&tree2==null)
            return true;
        if(tree1==null||tree2==null)
            return false;

        if(tree1.key!=tree2.key)
            return false;
        boolean left = isSame(tree1.left,tree2.left);
        boolean right = isSame(tree1.right,tree2.right);

        return left&&right;
    }
    /*
     * 判断是否是相同的树     ---非递归---
     * 遍历一遍即可
     * */
    public boolean isSame1(BSTNode<T>tree1,BSTNode<T>tree2){
        if(tree1==null&&tree2==null)
            return false;
        if(tree1==null||tree2==null)
            return false;

        Stack<BSTNode<T>> s1=new Stack<BSTNode<T>>();
        Stack<BSTNode<T>> s2=new Stack<BSTNode<T>>();

        s1.push(tree1);
        s2.push(tree2);

        while(s1.size()>0&&s2.size()>0){
            BSTNode<T> t1=s1.pop();
            BSTNode<T> t2=s2.pop();

            if(t1==null&&t2==null){
                continue;
            }else if(t1!=null&&t2!=null&&t1.key==t2.key){
                s1.push(t1.right);
                s1.push(t1.left);
                s1.push(t2.right);
                s1.push(t2.right);
            }else {
                return false;
            }           
        }
        return true;
    } 
    /*
     *八, 是否是平衡二叉树    ---递归---
     * 二叉树不为空,若左子树和右子树都是AVL树并且左子树和右子树高度相差不大于1,
     * */
    public boolean isAVL(){
        return isAVL(mRoot);
    }
    private boolean isAVL(BSTNode<T> tree){
        if(tree==null)
            return true;
        if(Math.abs(GetDep(tree.left)-GetDep(tree.right))>1){
            return false ;
        }

        return isAVL(tree.left)&&isAVL(tree.right);
    }
    //http://www.cnblogs.com/wenjiang/p/3321815.html#top
    //http://biaobiaoqi.github.io/blog/2013/04/27/pat1020-pat1043-rebuild-binary-tree/
    //http://blog.csdn.net/likebamboo/article/details/16845661
    /*十,输入某二叉树的前序遍历和中序遍历的结果,重建该二叉树
     * 假设前序遍历为{1, 2, 4, 7, 3, 5, 6, 8}, 中序遍历为{4, 7, 2, 1, 5, 3, 8, 6}
     * 可以知道,根节点为1,由中序遍历可知{4,7,2}为左节点,{5,3,8,6}位右节点
     * 
     * ps:搜索二叉树中节点根据大小的排序就是中序顺序,所以,题目还可以这样:
     * 输入树的前序遍历序列,判定该树是否是二叉搜索树或 BST 的镜像树,如果是,后序序列输出。
     * */

建立一个搜索二叉树,并后序遍历输出:
后序遍历非递归方式,参考:http://bookshadow.com/weblog/2015/01/19/binary-tree-post-order-traversal/

import java.util.Stack;


public class BinaryTree {

    private class BSTNode{

        int  key;
        BSTNode left;
        BSTNode right;


        public BSTNode(int key,BSTNode left,BSTNode right){

             this.key= key;
             this.left=left;
             this.right=right;
          }

     }

    private BSTNode  mRoot;//根结点
        //插入,建立新的二叉树
    public void insert(int key){
        BSTNode newNode = new BSTNode(key,null,null);
        //最终也要保证生成的根节点是整棵树的根,所以最后要把root return
        mRoot = insert(mRoot,newNode);

    }
    public BSTNode insert(BSTNode root,BSTNode newNode){

        if(root==null) root=newNode;

        if(newNode.key < root.key){
            root.left = insert(root.left,newNode);
        }else if(newNode.key > root.key){
            root.right = insert(root.right,newNode);
        }

        return root;
    }

    /*
     * 后序遍历
     * 维护一个visited标记
     * 判断栈顶元素。
     *    如果栈顶元素有右节点,并且不是刚刚被访问的节点,则将栈顶的右子树作为root,循环push
     *    如果栈顶无右子树,或者右子树被访问过,输出栈顶元素,修改pre元素
     *     
     * */
    public void PostSort(){

        PostSort(mRoot);

    }

    public void PostSort(BSTNode root){
        if(root==null)  return;

        Stack<BSTNode> s = new Stack<BSTNode>();
        BSTNode pre =null;

        while(root!=null||!s.isEmpty()){
            while(root!=null){
                s.push(root);
                root=root.left;
            }

            if(s.peek().right!=null&&s.peek().right!=pre){
                root = s.peek().right;
            }else{
                System.out.print(s.peek().key+" ");
                pre = s.pop();
            }
        }
    }

    public static void main(String[] args) {

        int [] arr ={7,3,5,6,1,9,11};
        BinaryTree bt = new BinaryTree();

        for(int i=0;i<arr.length;i++){
            bt.insert(arr[i]);
        }

        bt.PostSort();

    }

}

根据前序and中序,前序and 层序等构建二叉树以后再看。。。
关于二叉树的题目还有 是否是子树,镜像,二叉树两节点最大距离,最低公共祖先节点等等。。。

关于链表的题目集合: http://blog.csdn.net/fightforyourdream/article/details/16353519

参考链接:
http://blog.csdn.net/luckyxiaoqiang/article/details/7518888
http://www.gocalf.com/blog/traversing-binary-tree.html#id9
http://blog.csdn.net/fightforyourdream/article/details/16843303#comments
http://www.cnblogs.com/wenjiang/p/3321815.html#top

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章