Preface last night to add an int to the dictionary table in the Android application, using HashMap implementation, Eclipse gave a warning, last night, the project on-line tension, I directly ignored, today I looked at the specific eclipse hints as follows:
Use new sparsearray<string> (...) instead for better performance
This warning is meant to be replaced with Sparsearray to get better performance.
SOURCE because Sparsearray overall code is relatively simple, first show the source code, and then analyze why use sparsearray than using HashMap have better 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 won't * require any additional memory Allocati On to store the specified * number of mappings. If you supply an initial capacity of 0, the * sparse array would be 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> Clon e = 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 ha s 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 have been MA De. */@SuppressWarnings ("unchecked") public E get (int key, E valueifkeynotfound) {int i = Containerhelpers.bina Rysearch (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 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 mapping 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 an index of the range <code>0...size () -1</code>, returns * The key from the <code& gt;index</code>th Key-value mapping that this * Sparsearray stores. * * <p>the keys corresponding to indices in ascending order is guaranteed to * is in ascending order, e.g., <code>keyat (0) </code> would return the * smallest key and <code>keyat (size ()-1) </code> would re Turn the largest * key.</p> */public int Keyat (int index) {if (mgarbage) {GC (); } return Mkeys[index]; }/** * Given an index of the range <code>0...size () -1</code>, returns * The value from the <cod e>index</code>th Key-value mapping that this * Sparsearray stores. * * <p>the values corresponding to indices in ascending order is guaranteed * to is associated with keys 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 an index in the range <code>0...size () -1</code>, sets a new * value for the <code& gt;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 number if th E specified * key is not mapped. */public int indexofkey (int key) {if (mgarbage) {GC (); } return Containerhelpers.binarysearch (Mkeys, msize, key); }/** * Returns an index for which {@link #valueAt} would return the * specified key, or a negative number if n o keys map to the * specified value. * <p>beware that's a linear search, unlike lookups by key, * and that multiple keys can map to the same VA Lue and this would * find only one of them. * <p>note also that unlike most collections ' {@code indexOf} methods, * This method compares values using {@code = =} 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 was greater than all exist ing 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 + its mappings. If * This maps 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 (10); }/** * Creates a new sparsearray containing no mappings that won't * require any additional memory Allocati On to store the specified * number of mappings. If you supply an initial capacity of 0, the * sparse array would be 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; }
As you can see from the construction method, the size of the container is also pre-set, with a default size of 10.
Let's take a look at adding data operations:
/** * Adds A mapping from the specified key to the specified value, * Replacing the previous mapping 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++; } }
Look at the data again:
/** * Gets the Object mapped from the specified key, or <code>null</code> * If no such mapping have 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 have 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]; } }
As you can see, in the process of put data and get data, a binary lookup algorithm is called uniformly, which is the core of sparsearray 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, the method of (lo + hi) >>> 1 is somewhat odd, and it is better to use Lo + (Hi-lo)/2 directly.
Android Sparsearray Source Analysis