簡體   English   中英

使用AVL樹的地圖實現

[英]Map implementation using AVL tree

我正在嘗試使用AVL樹作為基礎結構來實現一個簡單的Map。 我使用二進制搜索樹作為基礎結構實現了Map,但是在描繪必要時如何檢查和平衡樹的過程中遇到了麻煩。 當我放入一個鍵值對時,我需要檢查樹的平衡並采取相應的措施。 我不確定該怎么做。 這是我的MyAVLMap代碼(來自二進制搜索樹實現)。 任何幫助表示贊賞!

這是我的課:

public class MyAVLMap<K, V> implements BasicMap<K, V> {

  // the root of the "tree" that structures the map
  private AVLNode root;

  // the number of key-value mappings currently in the map
  private int numKeys;

  /**
   * Constructs MyAVLMap object.
   */
  public MyAVLMap() {
    root = null;

    numKeys = 0;
  }

  /**
   * Associates the specified value with the specified
   * key in the current map.
   * 
   * @param key The key with which the specified value
   *            is to be associated.
   * @param value The value to be associated with the 
   *              specified key.
   */
  public void put(K key, V value){
    // input validation
    if(key == null || value == null) {
      throw new IllegalArgumentException();
    }

    root = put(root, (Comparable) key, value);
  }

//  // This helper method adds the specified key-value mapping
//  // to the tree rooted at "r".
//  @SuppressWarnings("unchecked")
//  private AVLNode put(AVLNode r, Comparable key, V value){
//    if(r == null) {
//      numKeys++;
//      return new AVLNode(key, value);
//    }
//    
//    int compare = key.compareTo(r.key);
//    if(compare == 0) {
//      r.value = value;
//    } else if(compare < 0) {
//      r.left = put(r.left, key, value);
//    } else {  // (compare > 0)
//      r.right = put(r.right, key, value);
//    }
//    
//    return r;
//  }  

  /**
   * Internal method to insert into a subtree.
   * 
   * @param x the item to insert.
   * @param t the node that roots the tree.
   * @return the new root.
   */
  @SuppressWarnings("unchecked")
  private AVLNode put(AVLNode r, Comparable key, V value)
  {
    if(r == null) {
      return new AVLNode(key, value);
    } else if(key.compareTo(r.key) < 0) {
      r.left = put(r.left, key, value);
      if((r.left.height - r.right.height == 2) &&
         (key.compareTo(r.left.key) < 0)) {
        r = rotateWithLeftChild(r);
      } else {
        r = doubleWithLeftChild(r);
      }
    } else if(key.compareTo(r.key) > 0 ) {
      r.right = put(r.right, key, value);
      if((r.right.height - r.left.height == 2) &&
         (key.compareTo(r.right.key) > 0)) {
        r = rotateWithRightChild(r);
      }
      else {
        r = doubleWithRightChild(r);
      }
    }

    // else: Duplicate; do nothing
    r.height = max(r.left.height, r.right.height) + 1;

    return r;
  }

  // This helper method returns the greater of two integers.
  private static int max(int n1, int n2)
  {
    if(n1 > n2) {
      return n1;
    } else {  // left <= right
      return n2;
    }
  }

  /**
   * Rotate binary tree node with left child.
   * For AVL trees, this is a single rotation for case 1.
   * Update heights, then return new root.
   */
  private AVLNode rotateWithLeftChild(AVLNode root2) {
    AVLNode root1 = root2.left;
    root2.left = root1.right;
    root1.right = root2;

    root2.height = max(root2.left.height, root2.right.height) + 1;
    root1.height = max(root1.left.height, root2.height) + 1;

    return root1;
  }

  /**
   * Rotate binary tree node with right child.
   * For AVL trees, this is a single rotation for case 4.
   * Update heights, then return new root.
   */
  private AVLNode rotateWithRightChild(AVLNode root1) {
    AVLNode root2 = root1.right;
    root1.right = root2.left;
    root2.left = root1;

    root1.height = max(root1.left.height, root1.right.height) + 1;
    root2.height = max(root2.right.height, root1.height) + 1;

    return root2;
  }

  /**
   * Double rotate binary tree node: first left child
   * with its right child; then node k3 with new left child.
   * For AVL trees, this is a double rotation for case 2.
   * Update heights, then return new root.
   */
  private AVLNode doubleWithLeftChild(AVLNode r) {
    r.left = rotateWithRightChild(r.left);

    return rotateWithLeftChild(r);
  }

  /**
   * Double rotate binary tree node: first right child
   * with its left child; then node r1 with new right child.
   * For AVL trees, this is a double rotation for case 3.
   * Update heights, then return new root.
   */
  private AVLNode doubleWithRightChild(AVLNode r) {
    r.right = rotateWithLeftChild(r.right);

    return rotateWithRightChild(r);
  }

  /**
   * Returns the value to which the specified key is mapped,
   * or <tt>null</tt> if the specified key is not mapped.
   * 
   * @param key The key whose associated value is to be returned.
   * @return The value to which the specified key is mapped,
   *         or <tt>null</tt> if the specified key is not mapped.
   */
  public V get(Object key){
    return get(root, (Comparable) key);
  }

  // This helper method retrieves the value associated with the
  // specified key in the tree rooted at "r".
  @SuppressWarnings("unchecked")
  private V get(AVLNode r, Comparable key){
    if(r == null) {
      return null;
    }

    int compare = key.compareTo(r.key);
    if(compare == 0) {
      return (V) r.value;
    } else if(compare < 0) {
      return get(r.left, key);
    } else {  // compare > 0
      return get(r.right, key);
    }
  }

  /**
   * Returns true if the current map contains a mapping for the
   * specified key.
   * 
   * @param key The key whose presence in the map is being tested.
   * @return If this map contains a mapping for the specified
   *        key.
   */
  public boolean containsKey(Object key) {
    return get((Comparable) key) != null;
  }

  /**
   * Returns true if the current map contains no key-value mappings.
   * 
   * @return If the current map contains no key-value mappings.
   */
  public boolean isEmpty() {
    return root == null;
  }

  /**
   * Removes all of the mappings from the current map.
   */
  public void clear() {
    root = null;

    numKeys = 0;
  }

  /**
   * Returns the number of key-value mappings in this map
   * @return The number of key-value mappings in this map
   */
  public int size(){
    return numKeys;
  }

  /**
   * Returns the String representation of this map.
   * 
   * @return The String representation of this map.
   */
  @Override
  public String toString() {
    return "(" + subtreeToString(root) + ")";
  }

  // This helper method returns a String representation of the contents
  // of the map for (sub-)tree with root "r".
  private String subtreeToString(AVLNode r) {
    String str = "";

    if(r == null) {
      return str;
    }

    str += r.key + ":" + r.value;
    str += " (" + subtreeToString(r.left) + ") (" + 
      subtreeToString(r.right) + ")";

    return str;
  }

  // This inner class creates each of the node(s) that
  // compose the AVL tree structure.
  class AVLNode<K, V> {

    /**
     * The key stored in the node.
     */
    public K key;

    /**
     * The corresponding value associated with a key in the node.
     */
    public V value;

    /**
     * The node to the left of "this" node.
     */
    public AVLNode left;

    /**
     * The node to the right of "this" node.
     */
    public AVLNode right;

    /**
     * The height of "this" node.
     */
    public int height;

    /**
     * Constructs the AVLNode object (four parameters).
     * 
     * @param key The key to be stored in the node.
     * @param value The corresponding value to be stored in the node.
     * @param left The node to the left of "this" node.
     * @param right The node to the right of "this" node.
     */
    @SuppressWarnings("unchecked")
    public AVLNode(Object key, Object value, AVLNode left, AVLNode right) {
      // bind to references
      this.key = (K) key;
      this.value = (V) value;
      this.left = left;
      this.right = right;

      height = 0;
    }

    /**
     * Constructs the AVLNode (two parameters).
     * 
     * @param key The key to be stored in the node.
     * @param value The corresponding value to be stored in the node.
     */
    public AVLNode(Object key, Object value) {
      // call three parameter constructor
      this(key, value, null, null);

      height = 0;
    }

  }

}

這是它實現的接口:

public interface BasicMap<K, V> {

    /**
     * Associates the specified value with the specified
     * key in the current map. Neither key nor value should
     * be <tt>null</tt>.
     * @param key The key with which the specified value
     * is to be associated.
     * @param value The value to be associated with the 
     * specified key.
     */
    public void put(K key, V value);

    /**
     * Returns the value to which the specified key is mapped,
     * or <tt>null</tt> if the specified key is not mapped.
     * @param key The key whose associated value is to be returned
     * @return The value to which the specified key is mapped,
     * or <tt>null</tt> if the specified key is not mapped.
     */
    public V get(Object key);

    /**
     * Returns true if the current map contains a mapping for the
     * specified key.
     * @param key The key whose presence in the map is being tested.
     * @return true if this map contains a mapping for the specified
     * key.
     */
    public boolean containsKey(Object key);

    /**
     * Returns true if the current map contains no key-value mappings.
     * @return true if the current map contains no key-value mappings.
     */
    public boolean isEmpty();

    /**
     * Removes all of the mappings from the current map.
     */
    public void clear();

    /**
     * Returns the number of key-value mappings in this map
     * @return The number of key-value mappings in this map
     */
    public int size();

    /**
     * Returns the String representation of this map
     * @return The String representation of this map
     */
    public String toString();

}

Fastutils中有這些數據結構的超酷實現,例如,參見Double2FloatAVLTreeMap類。

該庫是開源的,所以也許您想研究該代碼(這些年來仍然很感興趣)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM