1. 程式人生 > >AVL樹的實現(完整程式碼)

AVL樹的實現(完整程式碼)

AVL樹的實現

1.類的架構
public class AvlTree<T extends Comparable<? super T>> {
  private static class AvlNode<T> { 待實現 } // AVL樹的節點類
  
  private AvlNode<T> root; // 根節點就代表了一個AVL樹
  
  public void makeEmpty(){ root = null; }
  public boolean isEmpty(){ return root == null; }
  
  public
int height() { return height(root); } // 樹的深度 public boolean contains(T t){ return contains(t, root); } // 查詢 public void insert(T t){ root = insert(t, root); } // 插入 public void remove(T t){ root = remove(t, root); } // 刪除(返回boolean值可以用contains判斷) private int height(AvlNode<T> root){ 待實現 }
private AvlNode<T> contains(T t, AvlNode<T>){ 待實現 } private AvlNode<T> insert(T t, AvlNode<T>){ 待實現 } private AvlNode<T> remove(T t, AvlNode<T>){ 待實現 } private AvlNode<T> balance(AvlNode<T>){ 待實現 } private AvlNode<T> rotateWithLeft(AvlNode<
T>
){ 待實現 } private AvlNode<T> doubleWithLeft(AvlNode<T>){ 待實現 } private AvlNode<T> rotateWithRight(AvlNode<T>){ 待實現 } private AvlNode<T> doubleWithRight(AvlNode<T>){ 待實現 } }
2.static內部類:AvlNode
private static class AvlNode<T> {
  T element;
  AvlNode<T> left;
  AvlNode<T> right;
  int height; // 和普通二叉樹結點對比,多了高度資訊
  
  AvlNode(T t){ this(t,null,null); } 
  
  AvlNode(T t, AvlNode<T> le, AvlNode<T> ri){
    this.t = t;
    left = le; right = ri;
    height = 0; // 單個節點是沒有高度的,它的高度是改動(插入/刪除)時賦值的
  }
}
3.方法實現
private int height(AvlNode<T> root){
  return root==null?-1:root.height; // null節點高度是-1,樹葉節點高度是0
}

private boolean contains(T t, AvlNode<T> root){
  if(t == null)
    return false;
  
  int result = t.compareTo(root.element);
  
  if(result > 0)
    return contains(t, root.right);
  else if(result < 0)
    return contains(t, root.left);
  else
    return true;
}

private AvlNode<T> insert(T t, AvlNode<T> root){
  if(root == null)
    return new AvlNode<T>(t);
  
  int result = t.compareTo(root.element);
  
  if(result > 0)
    root.right = insert(t, root.right);
  else if(result < 0)
    root.left = insert(t, root.left);
  else {} // exist. do nothing.
    
  return balance(root); // 先插入再平衡,從低往高做平衡(第一個做平衡的是最深的節點)
}

private AvlNode<T> remove(T t, AvlNode<T> root){
  if(root == null)
    return null;
  
  int result = t.compareTo(root.element);
  
  if(result > 0)
    root.right = remove(t, root.right);
  else if(result < 0)
    root.left =  remove(t, root.left);
  else{
    if(root.left == null && root.right == null)
      return null;
    else if(root.left != null && root.right != null){
      root.element = findMin(root.right).element;
      root.right = remove(root.element, root.right);
    } else
      root = (root.left==null)?root.right:root.left; 
  }
  
  return balance(root); // 刪除後再平衡一下
}

private BinaryNode<T> findMin(BinaryNode<T> root){
  if(root == null)
    throw new Exception();
  
  if(root.left != null)
    return findMin(root.left);
  else
    return root;
}
3.平衡節點的方法
private static final int ALLOWED_IMBALANCE = 1; // 允許的不平衡程度
private AvlNode<T> balance(AvlNode<T> root){
  if(root == null)
	return null;
  
  if( height(root.left) - height(root.right) > ALLOWED_IMBALANCE){ 
    if(height(root.left.left) >= height(root.left.right)) // 單旋轉:左單轉
      // >=是因為刪除的時候可能存在的不平衡情況
      root = rotateWithLeft(root);
    else // 左雙旋轉
      root = doubleWithLeft(root);
  } else if(height(root.right) - height(root.left) > ALLOWED_IMBALANCE){ 
    if(height(root.right.right) >= height(root.right.left)) // 單旋轉:右單轉
      root = rotateWithRight(root);
    else // 右雙旋轉
      root = doubleWithRight(root);
  } else {} // balance.do nothing
  
  root.height = Math.max(height(root.left), height(root.right)) + 1; // 更新高度
  // 這個是有必要的,插入操作並沒有更新高度,靠的就是balance方法裡從低往高更新
  
  return root;
}

private AvlNode<T> rotateWithLeft(AvlNode<T> k1){
  AvlNode<T> k2 = k1.left;
  k1.left = k2.right;
  k2.right = k1;
  // 更新高度
  k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
  k2.height = Math.max(height(k2.left), k1.height) + 1;
  
  return k2;
}

private AvlNode<T> rotateWithRight(AvlNode<T> k1){
  AvlNode<T> k2 = k1.right;
  k1.right = k2.left;
  k2.left = k1;
  // 更新高度
  k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
  k2.height = Math.max(height(k2.right), k1.height) + 1;
  
  return k2;
}

private AvlNode<T> doubleWithLeft(AvlNode<T> k1){
  k1.left = rotateWithRight(k1.left);
  return rotateWithLeft(k1);
}

private AvlNode<T> doubleWithRight(AvlNode<T> k1){
  k1.right = rotateWithLeft(k1.right);
  return rotateWithRight(k1);
}
4.總結
AvlNode:有了深度height資訊,該資訊在balance方法裡更新.
--注意高度資訊是屬於每個Node的屬性.而不是Tree的屬性.Tree的深度認為是它根節點Node的高度
--null的高度為-1,不是0; 樹葉節點的高度是0(符合定義)
--節點高度的賦值都是在balance方法裡完成(確實也只有平衡樹需要深度資訊,普通樹不需要),解耦和.
--節點在變化時,注意它的高度也是變化的

Avl樹程式碼分離的思想:將插入操作(刪除操作)與平衡操作分離.它的插入操作(分離操作)和普通樹一樣,但是操作完都要進行平衡操作,變成平衡樹.

不平衡的條件:某節點n的左(右)子樹比右(左)子樹深度大,且超過1
balance:該方法是核心平衡方法,節點n不平衡的原因和平衡方法分為四種:
--節點n左兒子的左兒子高度超了: 節點n左轉方法(順時針)
--節點n右兒子的右兒子高度超了: 節點n右轉方法(逆時針)
--節點n左兒子的右兒子高度超了: 雙旋轉:節點n左兒子先右轉,節點n再左轉.
--節點n右兒子的左兒子高度超了: 雙旋轉:節點n右兒子先左轉,節點n再右轉