1. 程式人生 > >二叉搜尋樹與二叉平衡搜尋樹

二叉搜尋樹與二叉平衡搜尋樹

二叉平衡搜尋樹是一種特殊的二叉搜尋樹,其保持一定的平衡關係,要求每一個節點的左右子樹的高度不會相差超過1

1.下面是一到二叉平衡搜尋樹的題,leetcode108

題目描述:

將一個按照升序排列的有序陣列,轉換為一棵高度平衡二叉搜尋樹。

本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。

示例:

給定有序陣列: [-10,-3,0,5,9],

一個可能的答案是:[0,-3,9,-10,null,5],它可以表示下面這個高度平衡二叉搜尋樹:

      0
     / \
   -3   9
   /   /
 -10  5

解決思路:

思路一
按照AVL樹的正常處理程式碼,寫出AVL樹中的insert、balance等方法,實現將任意順序的數值插入此樹均可以,
上邊思路太繁瑣,AVL樹的實現需要很多程式碼,而且由於這種實現的AVL樹具有對任意資料的輸入能力,因此自然其執行較慢,沒有利用此題目中的有序升序陣列的特性。
思路二
中序遍歷
本題給出的數值是以一個按照升序排列的有序陣列,因此應該利用升序的特點
二叉搜尋平衡樹,中間節點的值大於左子樹中節點的值,小於右子樹中節點的值
因此每次講陣列中中間位置的數值插入中間節點,
左半塊的中間位置的數值插入左子節點,右半塊的中間位置的數值插入右子節點

程式碼:

思路一的程式碼,太繁瑣,執行速度太慢,但是這種思路需要掌握,這是比較完整的常用二叉平衡搜尋樹的寫法,對任意資料都有處理能力:

class Solution {
    //思路一
    //按照AVL樹的正常處理程式碼,寫出AVL樹中的insert、balance等方法,實現將任意順序的數值插入此樹均可以
    //上邊思路太繁瑣,AVL樹的實現需要很多程式碼
    //思路二
    //中序遍歷
    //本題給出的數值是以一個按照升序排列的有序陣列,因此應該利用升序的特點
    //二叉搜尋平衡樹,中間節點的值大於左子樹中節點的值,小於右子樹中節點的值
    //因此每次講陣列中中間位置的數值插入中間節點,
    //左半塊的中間位置的數值插入左子節點,右半塊的中間位置的數值插入右子節點
    public TreeNode sortedArrayToBST(int[] nums) {
        TreeNode root = null;
        for(int x : nums){
            root = insert(x, root);
        }
        
        return root;
    }
    private TreeNode insert(int x, TreeNode root){
        if(root == null){
            return new TreeNode(x);
        }
        int compareResult = x - root.val;
        if(compareResult < 0){
            root.left = insert(x, root.left);
        }
        else if(compareResult > 0){
            root.right = insert(x, root.right);
        }
        
        return balance(root);
    }
    private int height(TreeNode root){
        if(root == null){
            return -1;
        }
        return Math.max(height(root.left), height(root.right)) + 1;
    }
    private TreeNode balance(TreeNode root){
        if(root == null){
            return root;
        }
        if(height(root.left) - height(root.right) > 1){
            if(height(root.left.left) >= height(root.left.right)){
                root = leftChildOne(root);
            }
            else{
                root = leftChildTwo(root);
            }
        }
        else if(height(root.right) - height(root.left) > 1){
            if(height(root.right.right) >= height(root.right.left)){
                root = rightChildOne(root);
            }
            else{
                root = rightChildTwo(root);
            }
        }
        else{;}
        
        return root;
    }
    
    private TreeNode leftChildOne(TreeNode k2){
        TreeNode k1 = k2.left;
        k2.left = k1.right;
        k1.right = k2;
        
        return k1;
    }
    private TreeNode leftChildTwo(TreeNode k3){
        k3.left = rightChildOne(k3.left);
        
        return leftChildOne(k3);
    }
    private TreeNode rightChildOne(TreeNode k2){
        TreeNode k1 = k2.right;
        k2.right = k1.left;
        k1.left = k2;
        
        return k1;
    }
    private TreeNode rightChildTwo(TreeNode k3){
        k3.right = leftChildOne(k3.right);
        
        return rightChildOne(k3);
    }
}

思路二的程式碼,針對此題目輸入資料的特點,程式碼量小,執行快:

class Solution {
    //思路一
    //按照AVL樹的正常處理程式碼,寫出AVL樹中的insert、balance等方法,實現將任意順序的數值插入此樹均可以
    //上邊思路太繁瑣,AVL樹的實現需要很多程式碼
    //思路二
    //中序遍歷
    //本題給出的數值是以一個按照升序排列的有序陣列,因此應該利用升序的特點
    //二叉搜尋平衡樹,中間節點的值大於左子樹中節點的值,小於右子樹中節點的值
    //因此每次講陣列中中間位置的數值插入中間節點,
    //左半塊的中間位置的數值插入左子節點,右半塊的中間位置的數值插入右子節點
    public TreeNode sortedArrayToBST(int[] nums) {
        if(nums == null){
            return null;
        }
        
        return insert(nums, 0, nums.length-1);
    }
    private TreeNode insert(int[] nums, int lo, int hi){
        if(lo > hi){
            return null;
        }
        
        int mid = lo + (hi - lo)/2;
        TreeNode root = new TreeNode(nums[mid]);
        
        root.left = insert(nums, lo, mid-1);
        root.right = insert(nums, mid + 1, hi);
        
        return root;
    }
}