Android 移动端数据结构
## SparseArray
## SparseBooleanArray
## SparseIntArray
## SparseLongArray
* 位于android.util,Android 中的数据结构,针对移动端做了优化,在数据量比较少的情况下,性能会好过 HashMap,类似于 HashMap,key:int ,value:object 。
* 为什么性能会好:
1. key 和 value 采用数组进行存储。存储 key 的数组是 int 类型,不需要进行装箱操作。提供了速度。
2. 采用二分查找法,在插入进行了排序,所以两个数组是按照从小到大进行排序的。
3. 在查找的时候,进行二分查找,数据量少的情况下,速度比较快。
同时还有一个类:SparseArrayCompat,位于android.support.v4.util,与 SparseArray 一样的。
其中有好几个类似的数据结构:SparseBooleanArray(key:int, value:boolean), SparseIntArray(key:int, value:int), SparseLongArray(key:int, value:long). SparseArray 通过数组对 key , value 进行存储。
在 map Integers to Objects 方面进行了优化,所以比使用 HashMap 提高了性能,建议遇到key:int, value:object 的情况下使用。
构造方法:
默认构造方法中会创建长度为 10 的数组来分别储存 key 和 value。
可以自己在手动输入一个数字,来创建一个指定长度的数组来存储key 和 value。
增:
public void put(int key, E value) // 存储指定key 和指定value ,假如指定key 已经有了在映射中,替换掉已经存在的。 public void append(int key, E value) // 储存 key value 到数组,key 的索引应该大于数组中的已有索引
删:
public void delete(int key) // 删除指定key public void remove(int key) // 调用 delete 方法 public void removeAt(int index) // 删除指定索引 public void removeAtRange(int index, int size) //删除指定范围的索引 public void clear() //清空所有内容
改:
public void put(int key, E value) // 指定key 已存在的情况下,更新,不存在的情况下,增加 public void setValueAt(int index, E value) // 更新指定索引的 value
查:
public E get(int key) // 得到指定key 的 value,调用的是 get(int key, null) public E get(int key, E valueIfKeyNotFound) // 返回指定key 的value,没有的情况下,返回传入的默认值 public int indexOfKey(int key) // 传入key 的索引 public int indexOfValue(E value) // 传入 value 的索引 public int keyAt(int index) // 指定索引的 key public E valueAt(int index) //指定索引的 value
源码:
1 public class SparseArray<E> implements Cloneable { 2 private static final Object DELETED = new Object(); 3 private boolean mGarbage = false; 4 5 private int[] mKeys; 6 private Object[] mValues; 7 private int mSize; 8 9 /** 10 * Creates a new SparseArray containing no mappings. 11 */ 12 public SparseArray() { 13 this(10); 14 } 15 16 /** 17 * Creates a new SparseArray containing no mappings that will not 18 * require any additional memory allocation to store the specified 19 * number of mappings. If you supply an initial capacity of 0, the 20 * sparse array will be initialized with a light-weight representation 21 * not requiring any additional array allocations. 22 */ 23 public SparseArray(int initialCapacity) { 24 if (initialCapacity == 0) { 25 mKeys = EmptyArray.INT; 26 mValues = EmptyArray.OBJECT; 27 } else { 28 mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity); 29 mKeys = new int[mValues.length]; 30 } 31 mSize = 0; 32 } 33 34 @Override 35 @SuppressWarnings("unchecked") 36 public SparseArray<E> clone() { 37 SparseArray<E> clone = null; 38 try { 39 clone = (SparseArray<E>) super.clone(); 40 clone.mKeys = mKeys.clone(); 41 clone.mValues = mValues.clone(); 42 } catch (CloneNotSupportedException cnse) { 43 /* ignore */ 44 } 45 return clone; 46 } 47 48 /** 49 * Gets the Object mapped from the specified key, or <code>null</code> 50 * if no such mapping has been made. 51 */ 52 public E get(int key) { 53 return get(key, null); 54 } 55 56 /** 57 * Gets the Object mapped from the specified key, or the specified Object 58 * if no such mapping has been made. 59 */ 60 @SuppressWarnings("unchecked") 61 public E get(int key, E valueIfKeyNotFound) { 62 int i = ContainerHelpers.binarySearch(mKeys, mSize, key); 63 64 if (i < 0 || mValues[i] == DELETED) { 65 return valueIfKeyNotFound; 66 } else { 67 return (E) mValues[i]; 68 } 69 } 70 71 /** 72 * Removes the mapping from the specified key, if there was any. 73 */ 74 public void delete(int key) { 75 int i = ContainerHelpers.binarySearch(mKeys, mSize, key); 76 77 if (i >= 0) { 78 if (mValues[i] != DELETED) { 79 mValues[i] = DELETED; 80 mGarbage = true; 81 } 82 } 83 } 84 85 /** 86 * @hide 87 * Removes the mapping from the specified key, if there was any, returning the old value. 88 */ 89 public E removeReturnOld(int key) { 90 int i = ContainerHelpers.binarySearch(mKeys, mSize, key); 91 92 if (i >= 0) { 93 if (mValues[i] != DELETED) { 94 final E old = (E) mValues[i]; 95 mValues[i] = DELETED; 96 mGarbage = true; 97 return old; 98 } 99 } 100 return null; 101 } 102 103 /** 104 * Alias for {@link #delete(int)}. 105 */ 106 public void remove(int key) { 107 delete(key); 108 } 109 110 /** 111 * Removes the mapping at the specified index. 112 */ 113 public void removeAt(int index) { 114 if (mValues[index] != DELETED) { 115 mValues[index] = DELETED; 116 mGarbage = true; 117 } 118 } 119 120 /** 121 * Remove a range of mappings as a batch. 122 * 123 * @param index Index to begin at 124 * @param size Number of mappings to remove 125 */ 126 public void removeAtRange(int index, int size) { 127 final int end = Math.min(mSize, index + size); 128 for (int i = index; i < end; i++) { 129 removeAt(i); 130 } 131 } 132 133 private void gc() { 134 // Log.e("SparseArray", "gc start with " + mSize); 135 136 int n = mSize; 137 int o = 0; 138 int[] keys = mKeys; 139 Object[] values = mValues; 140 141 for (int i = 0; i < n; i++) { 142 Object val = values[i]; 143 144 if (val != DELETED) { 145 if (i != o) { 146 keys[o] = keys[i]; 147 values[o] = val; 148 values[i] = null; 149 } 150 151 o++; 152 } 153 } 154 155 mGarbage = false; 156 mSize = o; 157 158 // Log.e("SparseArray", "gc end with " + mSize); 159 } 160 161 /** 162 * Adds a mapping from the specified key to the specified value, 163 * replacing the previous mapping from the specified key if there 164 * was one. 165 */ 166 public void put(int key, E value) { 167 int i = ContainerHelpers.binarySearch(mKeys, mSize, key); 168 169 if (i >= 0) { 170 mValues[i] = value; 171 } else { 172 i = ~i; 173 174 if (i < mSize && mValues[i] == DELETED) { 175 mKeys[i] = key; 176 mValues[i] = value; 177 return; 178 } 179 180 if (mGarbage && mSize >= mKeys.length) { 181 gc(); 182 183 // Search again because indices may have changed. 184 i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); 185 } 186 187 mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); 188 mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); 189 mSize++; 190 } 191 } 192 193 /** 194 * Returns the number of key-value mappings that this SparseArray 195 * currently stores. 196 */ 197 public int size() { 198 if (mGarbage) { 199 gc(); 200 } 201 202 return mSize; 203 } 204 205 /** 206 * Given an index in the range <code>0...size()-1</code>, returns 207 * the key from the <code>index</code>th key-value mapping that this 208 * SparseArray stores. 209 * 210 * <p>The keys corresponding to indices in ascending order are guaranteed to 211 * be in ascending order, e.g., <code>keyAt(0)</code> will return the 212 * smallest key and <code>keyAt(size()-1)</code> will return the largest 213 * key.</p> 214 */ 215 public int keyAt(int index) { 216 if (mGarbage) { 217 gc(); 218 } 219 220 return mKeys[index]; 221 } 222 223 /** 224 * Given an index in the range <code>0...size()-1</code>, returns 225 * the value from the <code>index</code>th key-value mapping that this 226 * SparseArray stores. 227 * 228 * <p>The values corresponding to indices in ascending order are guaranteed 229 * to be associated with keys in ascending order, e.g., 230 * <code>valueAt(0)</code> will return the value associated with the 231 * smallest key and <code>valueAt(size()-1)</code> will return the value 232 * associated with the largest key.</p> 233 */ 234 @SuppressWarnings("unchecked") 235 public E valueAt(int index) { 236 if (mGarbage) { 237 gc(); 238 } 239 240 return (E) mValues[index]; 241 } 242 243 /** 244 * Given an index in the range <code>0...size()-1</code>, sets a new 245 * value for the <code>index</code>th key-value mapping that this 246 * SparseArray stores. 247 */ 248 public void setValueAt(int index, E value) { 249 if (mGarbage) { 250 gc(); 251 } 252 253 mValues[index] = value; 254 } 255 256 /** 257 * Returns the index for which {@link #keyAt} would return the 258 * specified key, or a negative number if the specified 259 * key is not mapped. 260 */ 261 public int indexOfKey(int key) { 262 if (mGarbage) { 263 gc(); 264 } 265 266 return ContainerHelpers.binarySearch(mKeys, mSize, key); 267 } 268 269 /** 270 * Returns an index for which {@link #valueAt} would return the 271 * specified key, or a negative number if no keys map to the 272 * specified value. 273 * <p>Beware that this is a linear search, unlike lookups by key, 274 * and that multiple keys can map to the same value and this will 275 * find only one of them. 276 * <p>Note also that unlike most collections' {@code indexOf} methods, 277 * this method compares values using {@code ==} rather than {@code equals}. 278 */ 279 public int indexOfValue(E value) { 280 if (mGarbage) { 281 gc(); 282 } 283 284 for (int i = 0; i < mSize; i++) 285 if (mValues[i] == value) 286 return i; 287 288 return -1; 289 } 290 291 /** 292 * Removes all key-value mappings from this SparseArray. 293 */ 294 public void clear() { 295 int n = mSize; 296 Object[] values = mValues; 297 298 for (int i = 0; i < n; i++) { 299 values[i] = null; 300 } 301 302 mSize = 0; 303 mGarbage = false; 304 } 305 306 /** 307 * Puts a key/value pair into the array, optimizing for the case where 308 * the key is greater than all existing keys in the array. 309 */ 310 public void append(int key, E value) { 311 if (mSize != 0 && key <= mKeys[mSize - 1]) { 312 put(key, value); 313 return; 314 } 315 316 if (mGarbage && mSize >= mKeys.length) { 317 gc(); 318 } 319 320 mKeys = GrowingArrayUtils.append(mKeys, mSize, key); 321 mValues = GrowingArrayUtils.append(mValues, mSize, value); 322 mSize++; 323 } 324 325 /** 326 * {@inheritDoc} 327 * 328 * <p>This implementation composes a string by iterating over its mappings. If 329 * this map contains itself as a value, the string "(this Map)" 330 * will appear in its place. 331 */ 332 @Override 333 public String toString() { 334 if (size() <= 0) { 335 return "{}"; 336 } 337 338 StringBuilder buffer = new StringBuilder(mSize * 28); 339 buffer.append('{'); 340 for (int i=0; i<mSize; i++) { 341 if (i > 0) { 342 buffer.append(", "); 343 } 344 int key = keyAt(i); 345 buffer.append(key); 346 buffer.append('='); 347 Object value = valueAt(i); 348 if (value != this) { 349 buffer.append(value); 350 } else { 351 buffer.append("(this Map)"); 352 } 353 } 354 buffer.append('}'); 355 return buffer.toString(); 356 } 357 }
## ArrayMap
* 与 SparseArray 类似