简介

HashMap是java里比较常用的一个集合类,我们常用其来缓存一些处理后的结果,但是在Android项目中,Eclipse却给出了一个 performance 警告。意思就是说用SparseArray<E>来替代,以获取更好性能。按住Ctrl点击进入SparseArray的源码,可以看出他是Android提供的一个工具类。路径为:android.util.SparseArray。

SparseArray是android里为<Interger,Object>这样的HashMap而专门写的类,目的是提高效率,其核心是折半查找函数(binarySearch)。
SparseBooleanArray、SparseIntArray、SparseLongArray都是SparseArray的特殊形式(不带泛型),其key为Interget,value为特定的类型。
在Android中,当我们需要定义HashMap<Integer,E>时,我们可以使用SparseArray<E>来取得更好的性能。
总体来说,它们都是类似map这样key-value的存储方式,但是由于查找的算法不一样,因此效率也各不同。
但要明白,没有说哪个一定是最好的,只有根据不同需求在不同场景去应用,才能获取较优的结果。

官方文档

/
* SparseArrays 利用integer去管理object对象。不像一个正常的object对象数组,它能在索引数中快速的查找到所需的结果。(这
* 句话是意译,原意是能在众多索引数中“撕开一个缺口”,为什么原文这么表达?下面会慢慢说清楚。)它比HashMap去通过Integer索引
* 查找object对象时在内存上更具效率,不仅因为它避免了用来查找的自动“装箱”的keys,并且它的数据结构不依赖额外的对象去
* 各个映射中查找匹配。
*
 * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
 * there can be gaps in the indices.  It is intended to be more memory efficient
* than using a HashMap to map Integers to Objects, both because it avoids
* auto-boxing keys and its data structure doesn't rely on an extra entry object
* for each mapping.

*
* 请注意,这个容器会保持它的映射关系在一个数组的数据结构中,通过二分检索法去查找key。(这里我们终于知道,为何这个工具类中,
* 提供的添加映射关系的操作中,key的类型必须是integer。因为二分检索法,将从中间“切开”,integer的数据类型是实现这种检索过程的保证。)
*
* 如果保存大量的数据,这种数据结构是不适合的,换言之,SparseArray这个工具类并不应该用于存储大量的数据。这种情况下,它的效率
* 通常比传统的HashMap更低,因为它的查找方法并且增加和移除操作(任意一个操作)都需要在数组中插入和删除(两个步骤才能实现)。
*
* 如果存储的数据在几百个以内,它们的性能差异并不明显,低于50%。
*
* (OK,那么光看Android官方的介绍我们就有初步结论了,大量的数据我们相对SparseArray会优先选择HashMap,如果数据在几百个这个数目,
 *  那么选择它们任意一个去实现区别不大,如果数量较少,就选择SparseArray去实现。 其实如果我们理解了二分法,就很容易了SparseArray的
 *  实现原理,以及SparseArray和HashMap它们之间的区别了。)
*
* <p>Note that this container keeps its mappings in an array data structure,
 * using a binary search to find keys.  The implementation is not intended to be appropriate for
* data structures
 * that may contain large numbers of items.  It is generally slower than a traditional
* HashMap, since lookups require a binary search and adds and removes require inserting
 * and deleting entries in the array.  For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>

 *   
* 为了提高性能,这个容器包含了一个实现最优的方法:当移除keys后为了立刻使它的数组紧密,它会“遗留”已经被移除(标记了要删除)的条目(entry) 。
* 所被标记的条目(entry)(还未被当作垃圾回收掉前)可以被相同的key复用,也会在垃圾回收机制当作所有要回收的条目的一员被回收,从而使存储的数组更紧密。
*
* (我们下面看源码就会发现remove()方法其实是调用delete()方法的。印证了上面这句话所说的这种优化方法。
* 因为这样,能在每次移除元素后一直保持数组的数据结构是紧密不松散的。)
*
* 垃圾回收的机制会在这些情况执行:数组需要扩充,或者映射表的大小被恢复,或者条目值被重新检索后恢复的时候。
 *   
* <p>To help with performance, the container includes an optimization when removing
* keys: instead of compacting its array immediately, it leaves the removed entry marked
 * as deleted.  The entry can then be re-used for the same key, or compacted later in
 * a single garbage collection step of all removed entries.  This garbage collection will
* need to be performed at any time the array needs to be grown or the the map size or
* entry values are retrieved.</p>

*
* 当调用keyAt(int)去获取某个位置的key的键的值,或者调用valueAt(int)去获取某个位置的值时,可能是通过迭代容器中的元素
* 去实现的。
*
* <p>It is possible to iterate over the items in this container using
* {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
* <code>keyAt(int)</code> with ascending values of the index will return the
* keys in ascending order, or the values corresponding to the keys in ascending
* order in the case of <code>valueAt(int)<code>.</p>
*/
public class SparseArray<E> implements Cloneable

稀疏数组

单纯从字面上来理解,SparseArray指的是稀疏数组(Sparse array),所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。

假设有一个9*7的数组,其内容如下:
 
在此数组中,共有63个空间,但却只使用了5个元素,造成58个元素空间的浪费。以下我们就使用稀疏数组重新来定义这个数组:

在稀疏数组中,第一部分所记录的是原数组的【行数】、【列数】以及【元素的使用个数】,第二部分所记录的是所使用的元素在原数组中的【位置】和【内容】。
经过压缩之后,原来需要声明大小为63的数组,而使用压缩后,只需要声明大小为6*3的数组,仅需18个存储空间。

SparseIntArray API

public class SparseIntArray implements Cloneable {
public SparseIntArray()//默认的大小是10
public SparseIntArray(int initialCapacity)
public SparseIntArray clone()
public int get(int key)//当找不到的时候,默认返回null。
public int get(int key, int valueIfKeyNotFound)//当找不到的时候,返回valueIfKeyNotFound
public void delete(int key)
public void removeAt(int index)//直接调用的delete(int key)
public void put(int key, int value)//在put数据之前,会先查找要put的数据是否已经存在,如果存在就是修改,不存在就添加
public int size()
public int keyAt(int index)//采用二分法查找键的位置,所以找不到时返回小于0的数值,而不是返回-1。返回的负值是表示它在找不到时所在的位置
public int valueAt(int index)
public int indexOfKey(int key)
public int indexOfValue(int value)//查看值所在位置,没有的话返回-1
public void clear()
public void append(int key, int value)
public String toString() 

SparseArray HashMap 稀疏数组 二分法的更多相关文章

  1. JAVA描述算法和数据结构(01):稀疏数组和二维数组转换

    本文源码:GitHub·点这里 || GitEE·点这里 一.基本简介 1.基础概念 在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵:与之相反, ...

  2. 你听过稀疏数组(sparseArray)吗?

    稀疏数组(sparseArray) 基本介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组. 稀疏数组的处理方法是: 1.记录数组一共有几行几列,有多少个不同的值 ...

  3. 稀疏数组SparseArray

    1 实际需求 1.1 需求提出 编写五子棋程序,有存盘退出和续上盘的功能. 实现思路: 存盘退出: 定义一个二维数组,默认值是0,黑子表示1,蓝子表示2,然后将二维数组通过流存储到文件中. 换言之:五 ...

  4. C#数据结构与算法系列(二):稀疏数组(SparseArray)

    1.介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组.    稀疏数组的处理方法是: 1.记录数组一共有几行几列,有多少个不同的值    2.把具有不同值的元素的 ...

  5. 稀疏数组(java实现)

    1.稀疏数组 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组. 稀疏数组的处理方法是: 1.1记录数组一共有几行几列,有多少个不同的值 1.2把具有不同值的元素的行列 ...

  6. java实现稀疏数组压缩

    package sparseArray; public class SparseArray { public static void main(String[] args) { // TODO Aut ...

  7. Java数据结构之稀疏数组(Sparse Array)

    1.需求 编写的五子棋程序中,有存盘退出和续上盘的功能.因为该二维数组的很多值是默认值0,因此记录了很多没有意义的数据,为了压缩存储所以采用稀疏数组. 2.基本介绍 当一个数组中大部分元素为0,或者为 ...

  8. 【学习总结】java数据结构和算法-第三章-稀疏数组和队列

    相关链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 稀疏数组 队列 稀疏数组 稀疏数组介绍 图示 应用实例 代码实现 SparseArray.java:与二 ...

  9. 数据结构 二维数组-->稀疏数组-->二维数组

    稀疏数组基本概念: 稀疏数组应用场景: 当一个数组大部分的元素为"0",或者为同一个值的数组时,可以使用稀疏数组来保存该数组 处理方法: 1>记录数组一共有几行几列,有多少不 ...

随机推荐

  1. (转)你知道Android也有安全模式吗?(地球人都知道了吧)

    使用PC时,我们习惯在安全模式下解决驱动的各种兼容性问题.而你是否又知道,Android手机同样存在安全模式,帮你解决APP的各种冲突问题. 很多Android手机用户都遇到过下面这种极端情况:因为第 ...

  2. bootstrap弹出框居中

    1.html页面(如果效果出不来,注意修改单引号) <!DOCTYPE html> <html lang="zh-CN"> <head> < ...

  3. 初涉JavaScript模式 (8) : 函数 【概述】

    什么是函数 函数,是一个大型程序中的某部份代码,由一个或多个语句块组成.它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性.(维基百科) 函数的特点 第一类对象 在JavaScript世界中 ...

  4. @font-face扒站的步骤

    今天模仿百度首页手机版的时候遇到的@font-face的问题,现在整理一下. 问题:图中红色区域,在拷贝F12样式的时候,并没有出现这些小图标.        图1:百度的效果             ...

  5. JS冒泡事件与处理

    JavaSciprt事件中有两个很重要的特性:事件冒泡以及目标元素. 事件冒泡: 当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发.这 一过程被 ...

  6. PHP图形计算器(计算三角形矩形周长面积)

    运用PHP面向对象的知识设计一个图形计算器,同时也运用到了抽象类知识,这个计算器可以计算三角形的周长和面积以及矩形的周长和面积.本图形计算器有4个页面:1.PHP图形计算器主页index.php;   ...

  7. 省队集训day6 A

    code: #include<cstdio> #include<iostream> #include<cmath> #include<cstring> ...

  8. Activity完整的生命周期

    首语:群里看到一位网友说:你能说出Activity的完整生命周期吗?看到这句话,我也在反思自己,我也是个fresh,所以想找个时间仔细的扒一扒Activity生命周期. 首先拿一张简单而又复杂的生命周 ...

  9. poj Monthly Expense

    http://poj.org/problem?id=3273 #include<cstdio> #include<cstring> #include<cmath> ...

  10. 玩死人不偿命的CLOUDSTACK

    玩过CLOUDSTACK(CS)的人,一定不会陌生下面的LOG: 2013-12-27 18:26:43,861 DEBUG [allocator.impl.FirstFitAllocator] (J ...