二叉搜尋樹與二叉平衡搜尋樹
阿新 • • 發佈:2018-12-16
二叉平衡搜尋樹是一種特殊的二叉搜尋樹,其保持一定的平衡關係,要求每一個節點的左右子樹的高度不會相差超過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;
}
}