In-depth analysis of the Android system Sparsearray source code _java

Source: Internet
Author: User

Objective
last night, to add an int to a string dictionary table in Android apps, Eclipse gave a warning that the project was on the line last night, and I just ignored it, and today I looked at the specific eclipse tips as follows:

  Use the new sparsearray<string> (...) instead for better performance 

This warning means using Sparsearray instead to get better performance.

Source
because Sparsearray overall code is relatively simple, first the source display, and then analyze why the use of Sparsearray will be better than the use of hashmap performance.

public class Sparsearray<e> implements cloneable {private static final Object DELETED = new Object (); 
   
    Private Boolean mgarbage = false; 
    Private int[] Mkeys; 
    Private object[] mvalues; 
   
    private int msize; 
     /** * Creates a new sparsearray containing no mappings. 
    * * Public Sparsearray () {this (10); }/** * Creates a new sparsearray containing no mappings that would not * require any additional Y allocation to store the specified * number of mappings. 
     If you are supply an initial capacity of 0, the * sparse array is initialized with a light-weight representation 
     * Not requiring any additional array allocations. */public Sparsearray (int initialcapacity) {if (initialcapacity = 0) {Mkeys = Containerhelpers.emp 
        ty_ints; 
      Mvalues = containerhelpers.empty_objects; else {initialcapacity = Arrayutils.idealintarraysize (Initialcapacity); 
        Mkeys = new Int[initialcapacity]; 
      Mvalues = new Object[initialcapacity]; 
    } msize = 0; @Override @SuppressWarnings ("unchecked") public sparsearray<e> Clone () {sparsearray< 
      E> clone = null; 
        try {clone = (sparsearray<e>) super.clone (); 
        Clone.mkeys = Mkeys.clone (); 
      Clone.mvalues = Mvalues.clone (); 
    catch (Clonenotsupportedexception cnse) {/* Ignore/} return clone; }/** * Gets the Object mapped from the specified key, or <code>null</code> * if no such 
     Mapping has been made. 
    */Public E get (int key) {return get (key, NULL); }/** * Gets the object mapped from the specified key, or the specified Object * If no such mapping h 
     As been made. */@SuppressWarnings ("unchecked") public E get (int key, E valueifkeynotfound) {int i = ContaInerhelpers.binarysearch (Mkeys, msize, key); 
      if (I < 0 | | mvalues[i] = = DELETED) {return valueifkeynotfound; 
      else {return (E) mvalues[i]; 
     }/** * Removes the mapping from the specified key, if there is any. 
   
      */public void Delete (int key) {int i = Containerhelpers.binarysearch (Mkeys, msize, key); 
          if (I >= 0) {if (Mvalues[i]!= DELETED) {mvalues[i] = DELETED; 
        Mgarbage = true; 
     /** * Alias for {@link #delete (int)}. 
    */public void remove (int key) {delete (key); 
     }/** * Removes the mapping at the specified index. 
        */public void RemoveAt (int index) {if (Mvalues[index]!= DELETED) {Mvalues[index] = DELETED; 
      Mgarbage = true; 
     }/** * Remove a range of mappings as a batch. * * @param index to begin At * @param size number of mappings to remove */public void Removeatrange (int index, int size) { 
      Final int end = Math.min (msize, index + size); 
      for (int i = index; i < end; i++) {RemoveAt (i); 
   
      }} private void GC () {//LOG.E ("Sparsearray", "GC start with" + msize); 
      int n = msize; 
      int o = 0; 
      Int[] keys = Mkeys; 
   
      Object[] values = mvalues; 
   
        for (int i = 0; i < n; i++) {Object val = values[i]; 
            if (Val!= DELETED) {if (i!= o) {Keys[o] = keys[i]; 
            Values[o] = val; 
          Values[i] = null; 
        } o++; 
      } Mgarbage = false; 
   
      Msize = O; 
    LOG.E ("Sparsearray", "GC End with" + msize); }/** * Adds a mapping from the specified key to the specified value, * Replacing the previous Mappin 
  G from the specified key if there   * was one. 
   
      */public void put (int key, E value) {int i = Containerhelpers.binarysearch (Mkeys, msize, key); 
      if (I >= 0) {Mvalues[i] = value; 
   
        else {i = ~i; 
          if (i < msize && mvalues[i] = = DELETED) {mkeys[i] = key; 
          Mvalues[i] = value; 
        Return 
   
          } if (Mgarbage && msize >= mkeys.length) {GC (); 
          Search again because indices may have changed. 
        i = ~containerhelpers.binarysearch (Mkeys, msize, key); 
   
          } if (Msize >= mkeys.length) {int n = arrayutils.idealintarraysize (msize + 1); 
          int[] Nkeys = new Int[n]; 
   
          object[] nvalues = new Object[n]; 
          LOG.E ("Sparsearray", "grow" + mkeys.length + "to" + N); 
          System.arraycopy (Mkeys, 0, Nkeys, 0, mkeys.length); 
  System.arraycopy (mvalues, 0, nvalues, 0, mvalues.length); 
          Mkeys = Nkeys; 
        Mvalues = nvalues; 
          } if (msize-i!= 0) {//LOG.E ("Sparsearray", "move" + (msize-i)); 
          System.arraycopy (Mkeys, I, Mkeys, i + 1, msize-i); 
        System.arraycopy (Mvalues, I, mvalues, i + 1, msize-i); 
        } Mkeys[i] = key; 
        Mvalues[i] = value; 
      msize++; 
     }/** * Returns the number of key-value mappings that this sparsearray * currently stores. 
      */public int size () {if (mgarbage) {GC (); 
    return msize;  }/** * Given A index in the range <code>0...size () -1</code>, returns * The key from the 
     <code>index</code>th Key-value mapping that this * Sparsearray stores. * <p>the keys corresponding to indices in ascending order are guaranteed to * is in ascending G., <code>keyat (0) </code> wilL RETURN the * Smallest key and <code>keyat (size ()-1) </code> 'll return the largest * key.</p& 
     Gt 
      */public int Keyat (int index) {if (mgarbage) {GC (); 
    return Mkeys[index]; }/** * Given A index in the range <code>0...size () -1</code>, returns * the value from T 
     He <code>index</code>th Key-value mapping the This * Sparsearray stores. * * <p>the values corresponding to indices in ascending order are guaranteed * to being associated with key s in ascending order, e.g., * <code>valueat (0) </code> would return the value associated with the * Smallest key and <code>valueat (size ()-1) </code> would return the value * associated with the largest key. 
        </p> * @SuppressWarnings ("unchecked") public E valueat (int index) {if (mgarbage) { 
      GC (); Return (E)Mvalues[index];  }/** * Given A index in the range <code>0...size () -1</code>, sets a new * value for the 
     <code>index</code>th Key-value mapping that this * Sparsearray stores. 
      */public void setvalueat (int index, E value) {if (mgarbage) {GC (); 
    } Mvalues[index] = value; }/** * Returns the index for which {@link #keyAt} would return the * specified key, or a negative nu 
     Mber if the specified * key is not mapped. 
      */public int indexofkey (int key) {if (mgarbage) {GC (); 
    Return Containerhelpers.binarysearch (Mkeys, msize, key); /** * Returns a index for which {@link #valueAt} would return the * specified key, or a negative n 
     umber if no keys map to the * specified value. * <p>beware that's a linear search, unlike lookups by key, * and that multiple keysCan map to the same value and this is only one of the them. * <p>note also that unlike most collections ' {@code indexOf} methods, * This method compares values using {@co 
     De = =} rather than {@code equals}. 
      * * public int indexofvalue (E value) {if (mgarbage) {GC (); 
   
      for (int i = 0; i < msize i++) if (mvalues[i] = = value) return i; 
    return-1; 
     }/** * Removes all key-value mappings from this sparsearray. 
      */public void Clear () {int n = msize; 
   
      Object[] values = mvalues; 
      for (int i = 0; i < n; i++) {values[i] = null; 
      } msize = 0; 
    Mgarbage = false;  }/** * Puts a Key/value pair into the array, optimizing for the "case where *" The key is greater than 
     All existing keys in the array. */public void append (int key, E value) {if (msize!= 0 &&Key <= Mkeys[msize-1]) {Put (key, value); 
      Return 
      } if (Mgarbage && msize >= mkeys.length) {GC (); 
      int pos = msize; 
   
        if (pos >= mkeys.length) {int n = arrayutils.idealintarraysize (pos + 1); 
        int[] Nkeys = new Int[n]; 
   
        object[] nvalues = new Object[n]; 
        LOG.E ("Sparsearray", "grow" + mkeys.length + "to" + N); 
        System.arraycopy (Mkeys, 0, Nkeys, 0, mkeys.length); 
   
        System.arraycopy (mvalues, 0, nvalues, 0, mvalues.length); 
        Mkeys = Nkeys; 
      Mvalues = nvalues; 
      } Mkeys[pos] = key; 
      Mvalues[pos] = value; 
    Msize = pos + 1; /** * {@inheritDoc} * * <p>this implementation composes a string by iterating over its Mappings. 
     IF * This map contains itself as a value, the string "(This map)" * would appear in its place. * * @Override Public String toString () {if (size () <= 0) {return ' {} '; 
      } StringBuilder buffer = new StringBuilder (msize * 28); 
      Buffer.append (' {'); 
        for (int i=0; i<msize; i++) {if (i > 0) {buffer.append (","); 
        int key = Keyat (i); 
        Buffer.append (key); 
        Buffer.append (' = '); 
        Object value = valueat (i); 
        if (value!= this) {buffer.append (value); 
        else {buffer.append ("(This Map)"); 
      } buffer.append ('} '); 
    return buffer.tostring (); 
 } 
  }


First, take a look at the Sparsearray constructor:

 /** 
   * Creates a new sparsearray containing no mappings. 
   * * Public 
  Sparsearray () {this 
    ; 
  } 
   
  /** 
   * Creates a new sparsearray containing no mappings that won't be 
   * require any additional memory allocation to Store the specified 
   * Number of mappings. If you are supply an initial capacity of 0, the 
   * Sparse array is initialized with a light-weight representation
   * not requiring any additional array allocations. 
   */Public 
  sparsearray (int initialcapacity) { 
    if (initialcapacity = 0) { 
      Mkeys = containerhelpers.empty_ INTS; 
      Mvalues = containerhelpers.empty_objects; 
    } else { 
      initialcapacity = arrayutils.idealintarraysize (initialcapacity); 
      Mkeys = new Int[initialcapacity]; 
      Mvalues = new object[initialcapacity]; 
    } 
    msize = 0; 
  } 

As you can see from the construction method, the size of the container is preset, and the default size is 10.

Let's take a look at the Add data operation:

  /** * Adds A mapping from the specified key to the specified value, * Replacing the previous mapping from the S 
   Pecified Key if there * was one. 
   
    */public void put (int key, E value) {int i = Containerhelpers.binarysearch (Mkeys, msize, key); 
    if (I >= 0) {Mvalues[i] = value; 
   
      else {i = ~i; 
        if (i < msize && mvalues[i] = = DELETED) {mkeys[i] = key; 
        Mvalues[i] = value; 
      Return 
   
        } if (Mgarbage && msize >= mkeys.length) {GC (); 
        Search again because indices may have changed. 
      i = ~containerhelpers.binarysearch (Mkeys, msize, key); 
   
        } if (Msize >= mkeys.length) {int n = arrayutils.idealintarraysize (msize + 1); 
        int[] Nkeys = new Int[n]; 
   
        object[] nvalues = new Object[n]; 
        LOG.E ("Sparsearray", "grow" + mkeys.length + "to" + N); System.arraycopy (Mkeys, 0, Nkeys, 0, mkeys.length); 
   
        System.arraycopy (mvalues, 0, nvalues, 0, mvalues.length); 
        Mkeys = Nkeys; 
      Mvalues = nvalues; 
        } if (msize-i!= 0) {//LOG.E ("Sparsearray", "move" + (msize-i)); 
        System.arraycopy (Mkeys, I, Mkeys, i + 1, msize-i); 
      System.arraycopy (Mvalues, I, mvalues, i + 1, msize-i); 
      } Mkeys[i] = key; 
      Mvalues[i] = value; 
    msize++; 

 } 
  }


The way to look at the data again:

  /** 
   * Gets the Object mapped from the specified key, or <code>null</code> 
   * If no such mapping has bee N made. 
   */Public 
  E get (int key) {return get 
    (key, NULL); 
  } 
   
  /** 
   * Gets The object mapped from the specified key, or the specified Object 
   * If no such mapping has been 10/>*/ 
  @SuppressWarnings ("unchecked") public 
  E get (int key, E valueifkeynotfound) { 
    int i = Containerhelpers.binarysearch (Mkeys, msize, key); 
   
    if (I < 0 | | mvalues[i] = = DELETED) {return 
      valueifkeynotfound; 
    } else {return 
      (E) mvalues[i]; 
    } 
  } 


You can see that in the process of put data and get data, a binary lookup algorithm is uniformly invoked, which is the core of Sparsearray's ability to improve efficiency.

 static int BinarySearch (int[] array, int size, int value) { 
    int lo = 0; 
    int hi = size-1; 
   
    while (lo <= hi) { 
      final int mid = (lo + hi) >>> 1; 
      Final int midval = Array[mid]; 
   
      if (Midval < value) { 
        lo = mid + 1; 
      } else if (Midval > value) { 
        hi = mid-1; 
      } else { 
        return Mid Value found 
      } 
    } return 
    ~lo//value not present 
  } 

Personally think (lo + hi) >>> 1 method is somewhat strange, directly with Lo + (Hi-lo)/2 better.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.