zoukankan      html  css  js  c++  java
  • 算法导论:二叉搜索树

    定义:

    (0)二叉树

    (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

    (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

    (3)左、右子树也分别为二叉排序树

    数据结构定义

    public class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;
    
        public TreeNode(int val){
            this.val = val;
            this.left = left=null;
            this.right = right=null;
        }
    }

    插入元素

    由于元素互异,插入元素的位置一定在叶子结点,递归插入程序

        public TreeNode insertTree(TreeNode root,int key){
            if(root == null){
                root = new TreeNode(key);
                return root;
            }else if(key < root.val){
                root.left = insertTree(root.left,key);
            }else{
                root.right = insertTree(root.right,key);
            }
            return root;
        }

    查找最小值

    根据二叉搜索树的定义:左孩子比根节点小,右孩子比根节点大,最小值一定在最左的子树上,同时该子树一定没有左孩子,可以一直left的找

        /**
         * 递归找最小值
         * @param root
         * @return
         */
        public TreeNode iterativeTreeMin(TreeNode root){
            if(root.left!=null&&root.left.left==null)
                return root.left;
            return iterativeTreeMin(root.left);
        }
        /**
         * 查找最小节点,最小节点一定在下层的最左侧,同时该节点不能有左孩子
         * 时间复杂度O(h)
         * @param root
         * @return
         */
        public TreeNode treeMin(TreeNode root){
            while(root.left!=null){
                root = root.left;
            }
            return root;
        }

    查找最大值

    最大值一定在最右的子树,同时这个子树一定没有右孩子

        /**
         * 递归查找最大值
         * @param root
         * @return
         */
        public TreeNode iterativeTreeMax(TreeNode root){
            if(root.right!=null&&root.right.right==null)
                return root.right;
            return iterativeTreeMax(root.right);
        }
        /**
         * 查找最大结点,最大结点一定在下层的最右侧,同时该节点不能有右孩子
         * 时间复杂度O(h)
         * @param root
         * @return
         */
        public TreeNode treeMax(TreeNode root){
            while(root.right!=null){
                root = root.right;
            }
            return root;
        }

    查找结点是否存在

    递归和非递归

        /**
         * 循环方式查找 key是否在排序二叉树中
         * 这个效率更高,具体多少?
         * @param root
         * @param key
         * @return
         */
        public TreeNode iterativeTreeSearch(TreeNode root,TreeNode key){
            while(root!=null &&root.val!=key.val){
                if(key.val < root.val)
                    root = root.left;
                else
                    root = root.right;
            }
            return root;
        }
        /**
         * 递归查找 key节点是否在二叉树root中.
         * 时间复杂度O(h)
         * @param root
         * @param key
         * @return
         */
        public TreeNode treeSearch(TreeNode root,TreeNode key){
            if(key == null || key.val == root.val){
                return key;
            }
            if(key.val < root.val)
                return treeSearch(root.left,key);
            else
                return treeSearch(root.right,key);
        }

    前序遍历

    遍历规则:根左右

        /**
         * 递归前序遍历
         * @param root
         * @param result
         */
        public void preorderTree(TreeNode root,ArrayList<Integer> result){
            if(root==null)
                return;
            result.add(root.val);
            preorderTree(root.left,result);
            preorderTree(root.right,result);
        }

    递归的一般都能写出来,如何写出非递归程序?

    遍历规则:根左右

    对两层三个结点情况:先输出根结点,在输出左结点的时候需要先保存右结点的值,输出左结点,再输出保存的右结点

    对树的层数多的时候,这里需要保存右结点所在的子树,输出左结点值,对左结点同上操作。

    这里利用栈保存中间结点。

        /**
         * 循环前序遍历
         * @param root
         * @param result
         */
        public void iterativePreorderTree(TreeNode root,ArrayList<Integer> result){
            Stack<TreeNode> stack = new Stack<TreeNode>();
            while(root!=null || !stack.empty()){
                result.add(root.val);
                if(root.right!=null)
                    stack.push(root.right);
                root = root.left;
                if(root == null && !stack.empty()){
                    root = stack.pop();
                }
            }
        }

    中序遍历

    遍历规则:左根右

    递归很简单

        /**
         * 递归中序遍历二叉树
         * 时间复杂度O(N)
         * @param root
         * @param result
         */
        public  void inorderTree(TreeNode root,ArrayList<Integer> result){
            if(root == null)
                return;
            inorderTree(root.left,result);
            result.add(root.val);
            inorderTree(root.right,result);
        
        }

    非递归方式,需要利用栈保存左结点信息

        /**
         * 循环方式中序遍历,用栈存放中间节点
         * @param root
         * @param result
         */
        public void iterativeInorderTree(TreeNode root,ArrayList<Integer> result){
            Stack<TreeNode> stack = new Stack<TreeNode>();
            while(root!=null || !stack.empty()){
                while(root!=null){ // 向左侧走
                    stack.push(root);
                    
                    root = root.left;
                }
                root = stack.pop();// 取出最左侧的结点
                
                result.add(root.val);
                
                root = root.right; // 最左侧节点的右节点,若不存在在上面的while循环也会运行
            }
        }

    后序遍历

    遍历规则:左右根

    递归方式

        /**
         * 递归后续遍历
         * @param root
         * @param result
         */
        public void postorderTree(TreeNode root,ArrayList<Integer> result){
            if(root == null)
                return;
            postorderTree(root.left,result);
            postorderTree(root.right,result);
            result.add(root.val);
        }

    非递归

    理解不透

    /**
         * 非递归后序遍历
         * @param root
         * @param result
         */
        public void iterativePostorderTree(TreeNode root,ArrayList<Integer> result){
             
            Stack<TreeNode> stack = new Stack<TreeNode>();
            if (root == null) return;
            boolean flag = true;
            while(flag){  
                while(root.left != null || root.right != null){  
                    if (root.left != null){  
                        stack.push(root);  
                        root = root.left;  
                    }  
                    else{  
                        stack.push(root);  
                        root = root.right;  
                    }  
                }  
                TreeNode y = stack.peek();  
                while (root == y.right || y.right == null){  
                    result.add(root.val);  
                    stack.pop();
                    if (stack.empty()){  
                        flag = false;  
                        result.add(y.val);  
                        break;  
                    }  
                    root = y;  
                    y = stack.peek();  
                }  
                if (root == y.left && y.right != null){  
                    result.add(root.val);  
                    root = y.right;  
                }  
            }  
        }

    版本2

        /**
         * 后序遍历非递归 2 
         * @param root
         * @param result
         */
        public void iterativePostorderTree2(TreeNode root,ArrayList<Integer> result){
                Stack<TreeNode> stack = new Stack<TreeNode>();
                TreeNode prev = null; // previously traversed node
                TreeNode curr = root;
    
                if (root == null) {
                    return;
                }
    
                stack.push(root);
                while (!stack.empty()) {
                    curr = stack.peek();
                    if (prev == null || prev.left == curr || prev.right == curr) { // traverse down the tree
                        if (curr.left != null) {
                            stack.push(curr.left);
                        } else if (curr.right != null) {
                            stack.push(curr.right);
                        }
                    } else if (curr.left == prev) { // traverse up the tree from the left
                        if (curr.right != null) {
                            stack.push(curr.right);
                        }
                    } else { // traverse up the tree from the right
                        result.add(curr.val);
                        stack.pop();
                    }
                    prev = curr;
                }
    
        }

    求树的深度

    递归

        /**
         * 递归求树的深度
         * @param root
         * @param hight
         * @return
         */
        public int depth(TreeNode root,int hight){
            if(root == null)
                return hight;
            return Math.max(depth(root.left,hight), depth(root.right,hight))+1;
        }

    层次遍历

    规则:每一次打印一个结点的时候,如果该结点有子结点,则把该结点的子结点放到一个队列的尾部。接下来到队列的头部取出最早进入队列的结点。

    重复前面的打印操作,直到队列中所有的结点都被打印出来为止。

        public void levelOrder(TreeNode root,ArrayList<ArrayList<Integer>> tree){
             Queue<TreeNode> queue = new LinkedList<TreeNode>();
                
                if(root == null)
                    return ;
                queue.offer(root);
                while(!queue.isEmpty()){
                    ArrayList<Integer> list = new ArrayList<Integer>();
                    int size = queue.size();
                    for(int i=0;i<size;i++){
                        TreeNode head = queue.poll();
                        list.add(head.val);
                        if(head.left!=null){
                            queue.offer(head.left);
                        }
                        if(head.right!=null){
                            queue.offer(head.right);
                        }
                    }
                    tree.add(list);
                }
        }
  • 相关阅读:
    ArcPad 10 的安装部署
    各种机械键盘轴的差别,究竟什么轴好
    default argument given of parameter 的问题
    Quartz中时间表达式的设置-----corn表达式
    图像切割之(一)概述
    SMTP协议分析
    Android学习小Demo(19)利用Loader来实时接收短信
    qml动画控制器AnimationController
    httpclient 文件上传
    Java习题10.24
  • 原文地址:https://www.cnblogs.com/theskulls/p/5510347.html
Copyright © 2011-2022 走看看