Foreword
Last night I wanted to add an INT to the String's dictionary table in the Android application. When it was implemented with HashMap, Eclipse gave a warning. Last night, the project was tightly launched. I just ignored it. I took a look at the specific Eclipse notice today. as follows:
Use new sparsearray <string> (...) Instead for better performance
This warning means to replace it using Sparsearray to get better performance.
Source code
Because the overall code of Sparsearray is relatively simple, first show the source code, and then analyze why use Sparsearray has better performance than using HashMap.
Public Class Sparsearray <E> Implements Cloneable {Private Static Final Object Deleted = New Object (); Private Boolean MgarBage = False; s; s;; containing no mappings. * / Public Sparsearray () {this (10);} / ** * Creates a new Sparsearray Conaining no mappings that will not even * Require any y allCation to stop the specify * number of mappings. If you support Initial Capacity of 0, The * Spars Array Will Be Initialized with A Light-WEIGHT RePRESENTATION * Not Requering ARLOCATIONS. */ Pub LIC Sparsearray (int initialCapAcity) {if (initialCapAcity == 0) {mKEYS = Containerhelpers.empty_ints; mvalues = ContainerHelpers.empty_Objects;} Else {initialCapAcity = ArrayUTILS.IDEALINTARRAYSIZE (initialCapAcity); City]; 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.clon e () ;} Catch (ClonenotSupportedException CNSE) { /* IGNORE* /} Return Clone;} /*** gets the object mapd from the specification key, or < /null < / code> * if no such mapping has ben made. * / Public E get (int key) {Return Get (key, null);} / ** * gets the object mapped from the specified key, or the specify object * if no such ping has made. */ @suppressWarnings (" Unched ")) Public E get (int key, e valueifnynotfound) {int i = Containerhelpers.binarySearch (MKEYS, MSIZE, KEY); if (i <0 || mvalues [i] == TED) {Return valueIFKEYNOTFOUND;} else { Return (e) mvalues [i];} / ** * Removes the mapping from the specify key, if there was any. * / Public void delete (int Key) {int i = Containerhelp Ers.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 maping at the specify index. */ Public Void Removeat (INDEX) {if (m) Values [Index]! = DELETED) { mvalues [index] = deleted; mgarbage = true;} /** * remove 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 VIID 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 value = valueS [i]; if (value! = deleted) {if (i! = o) {key [o] = keys [i]; valus [o] = values [i ] = null;} o ++;}} mgarbage = false; msize = o; // log.e ("sparsearray", "GC End with"+msize); ey to the Specified Value, * RepLacing the Previous Mapping from the Specified Key if there is one. */ Public void put (int key, E value) {int i = Containerhelp Ers.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 IndIARES May Have Changed. I = ~ Containerhelpers.binarysearch (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", "gro" w " + mkeys .length + "to" + n); System.arrayCopy (MKEYS, 0, NKEYS, MKEYS.Length); System.arrayCopy (MVALUES, 0, Nvalues, 0, MVALUES.Length); ys; 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 ++; of key -Value Mappings That this Sparsearray * CurrenTly Stores. * / Public int Size () {GC ();} Return msize;} / ** * ** * given in the Ange <code> 0 ... size () -1 </code>, Returns * The Key from the <Code> Index </code> Th Key-Value MAPPING That this * Sparsearray Stores. CES in Ascending Order Are Guaranteed TO * Be in Ascending Order, EG, <Code> Keyat (0) </Code> Will Return the * Smallest key and <Code> keyat (size ()-1) </code> Will Return the larges * key. < / / P> * / Public int Keyat (int index) {if (mgarbage) {gc ();} Return Mkeys [Index];} / ** * given an index in the range <code> 0 ... size ()- 1 </code>, RETURNS * The Value from the <Code> Index </code> Th Key-Value Mapping that this * Sparsearray Stores. * * <p> The Valuespondid TO ES in Ascending Order are guarantech * to be associated With keys in Ascending Order, EG, * <Code> Valueat (0) </code> Will Return the value associated with the * Smallest Key and Value (size ()-1) </c. ODE> Will Return the value * associated with the larget key. </ P> */ @SuppressWarnings ("Uncheck") PUBLIC E VALUEAT (INT Index) {if (mgarbage) {gc ();} Return (E) ES [Index];} /* * * Given An 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 ST. os . * / Public Void SetValueat (int index, e value) {if (mgarbage) {gc ();} mvalues [Index] = Value;} / ** * reTURNS The Index For which {@link {@link #Keyat} WOULD RETURN The * Specified Key, or a Negative Number If the Specified * key is not mapped. */ Public INDEXOFKEY (Int key) {if (mgarbage) {gc ();} Return C onTainerHelpers.binarySearch (MKEYS, Msize, Key);} /** * Returns An Index for Which {@Link #Valueat} Would Return the * Specified Key, or a Negative Number if no keys map to the * SPECIFIED VALUE. * <p> Beware that this is a linear search, unlike lookups By Key, * and that Multiple Keys Can Map to the Same Value and this Will * Find only one of them. * <p> Note Also That UNLIKE MOST COLLECTIONS exof} methods, * this method compares value using {@ CODE ==} Rather than {@Code Equals}. */ Public int Indexofvalue (E value) {if (mgarbage) {gc ();} for (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 [] va. lues = mvalues; for (int i = 0; I <n; i ++) {value [i] = null;} msize = 0; mgarbage = false;} /*** puts a key /value pair into the array, e * the key Is Greater than All Existing Keys in the Array. */ Public Void Append (int key, E Value) {if (msize! = 0 &&K <= msize -1]) {put (key, value) ; Return; } if (mKEYS.Length) {gc ();} int POS = msize; if (pOS> = mKEYS.LENGTH) {int n = ArrayalInTarraySize (POS + 1) ; int [] nkeys = new int [n]; object [] nvalues = new object [n]; // log.e ("sparsearray", "grow" + mKEYS.Length + "to" + n); 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 itseel as a value, the st Ring "(this map)" * Will APPEAR in ITS Place. */ @Override Public String Tostring () {if (size () <= 0) {Return "{}";} StringBuilder Buffer = New StringBuilder (msize * 28) ; buffer.append ('{' ); free (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 ("(" ("(" end ('}'); Return buffer.tostring ();}}
First, look at the constructor of Sparsearray:
/*** Creates a New Sparsearray containing no mappings.* /Public Sparsearray () {this (10);} /*** Creates a new Sparsearray NO MAPPINGS that Will * Require Any Additional Memory Alocation to Store The Specified * Number of Mappings. If you support an initial capacity of 0, The * Spars Array Will be Initialized with a Light-weight repressation DDITIONAL ARRAY Allocations. */ Public Sparsearray (int initialCapAcity) {if (InitialCapAcity == 0) {mKEYS = Containerhelpers.empty_ints; mvalues = Containerhelpers.empty_Objects;} Else {initialCapAcity = ArrayalInTarraySize IALCAPACITY); MKEYS = New intIt can be seen from the constructor that the size of the container is set in advance, and the default size is 10.
Let's take a look at the adding data operation:
/ ** * ADDS A MAPPING from the Specified Key to the Specify Value, * Replating the Previous Mapping from the Specified Key if there one one. */ Publi. c 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 becapes may have changed. ainerhelpers.binarySearch (MKEYS, MSIZE, MSIZE, key);} if (msize> = mKEYS.Length) {int n = arrayUtils.IDEALINTARRAYSIZE (msize + 1); int [] nkeys = new int [n]; ect [n]; // Log.e ("Sparsearray", "Grow" + MKEYS.Length + "to" + N); System.arrayCopy (MKEYS, 0, NKEYS, MKEYS.Length); ES, 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 method of checking the data:
/** * Gets the object mapped from the specify key, or <code> null </code> * if no such mapping. */Public E get (int key) {Return get (key, null);} / ** * gets the object mapped from the specified key, or the specify object * if no such maping has made. */ @Suppresswarnings) 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];}}
It can be seen that in the process of PUT data and GET data, a dual -point search algorithm is uniformly called. In fact, this 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; 1; 1; 1; 1; 1; 1; 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} I personally think that the method of (LO + Hi) >>> 1 is a bit weird, and it is better to use Lo + (Hi -LO) / 2 directly.