當用到Map的使用,用SparseArray替代性能更好

懶得自己整理了,直接轉一個博客了
鏈接

https://liuzhichao.com/p/832.html

HashMap是java裏比較常用的一個集合類,我比較習慣用來緩存一些處理後的結果。最近在做一個Android項目,在代碼中定義這樣一個變量,實例化時,Eclipse卻給出了一個 performance 警告。
這裏寫圖片描述
意思就是說用SparseArray 來替代,以獲取更好性能。

SparseArray更加高效在於他們避免了對key與value的autobox自動裝箱,並且避免了裝箱後的解箱,並使用二分法查找

老實說,對SparseArray並不熟悉,第一感覺應該是Android提供的一個類。按住Ctrl點擊進入SparseArray的源碼,果不其然,確定是Android提供的一個工具類。
這裏寫圖片描述
單純從字面上來理解,SparseArray指的是稀疏數組(Sparse array) ,所謂稀疏數組就是數組中大部分的內容值都未被使用(或都爲零),在數組中僅有少部分的空間使用。因此造成內存空間的浪費,爲了節省內存空間,並且不影響數組中原有的內容值,我們可以採用一種壓縮的方式來表示稀疏數組的內容。

假設有一個9*7的數組,其內容如下:
這裏寫圖片描述

在此數組中,共有63個空間,但卻只使用了5個元素,造成58個元素空間的浪費。以下我們就使用稀疏數組重新來定義這個數組:
這裏寫圖片描述
其中在稀疏數組中第一部分所記錄的是原數組的列數和行數以及元素使用的個數、第二部分所記錄的是原數組中元素的位置和內容。經過壓縮之後,原來需要聲明大小爲63的數組,而使用壓縮後,只需要聲明大小爲6*3的數組,僅需18個存儲空間。

繼續閱讀SparseArray的源碼,從構造方法我們可以看出,它和一般的List一樣,可以預先設置容器大小,默認的大小是10:

  public SparseArray() {
        this(10);
    }
    public SparseArray(int initialCapacity) {
        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
        mKeys = new int[initialCapacity];
        mValues = new Object[initialCapacity];
        mSize = 0;
    }

再來看看它對數據的”增刪改查”。

它有兩個方法可以添加鍵值對:

public void put(int key, E value) {}
 public void append(int key, E value){}

有四個方法可以執行刪除操作:

 public void delete(int key) {}
 public void remove(int key) {} //直接調用的delete(int key)
 public void removeAt(int index){}
 public void clear(){}

修改數據起初以爲只有setValueAt(int index, E value)可以修改數據,但後來發現put(int key, E value)也可以修改數據,我們查看put(int key, E value)的源碼可知,在put數據之前,會先查找要put的數據是否已經存在,如果存在就是修改,不存在就添加。

public void put(int key, E value) {
        int i = binarySearch(mKeys, 0, mSize, key);
        if (i > = 0) {
            mValues[i] = value;
        } else {
            i = ~i;
            if (i  < mSize &amp;&amp; mValues[i] == DELETED) {
                mKeys[i] = key;
                mValues[i] = value;
                return;
            }
            if (mGarbage &amp;&amp; mSize > = mKeys.length) {
                gc();
                // Search again because indices may have changed.
                i = ~binarySearch(mKeys, 0, mSize, key);
            }
            …………

所以,修改數據實際也有兩種方法

public void put(int key, E value)
 public void setValueAt(int index, E value)

最後再來看看如何查找數據。有兩個方法可以查詢取值:
public E get(int key)
public E get(int key, E valueIfKeyNotFound)

其中get(int key)也只是調用了 get(int key,E valueIfKeyNotFound),最後一個從傳參的變量名就能看出,傳入的是找不到的時候返回的值.get(int key)當找不到的時候,默認返回null。

查看第幾個位置的鍵:public int keyAt(int index)
有一點需要注意的是,查看鍵所在位置,由於是採用二分法查找鍵的位置,所以找不到時返回小於0的數值,而不是返回-1。返回的負值是表示它在找不到時所在的位置。

查看第幾個位置的值:
public E valueAt(int index)
查看值所在位置,沒有的話返回-1:
public int indexOfValue(E value)
最後,發現其核心就是折半查找函數(binarySearch),算法設計的很不錯。

private static int binarySearch(int[] a, int start, int len, int key) {
        int high = start + len, low = start - 1, guess;
        while (high - low >  1) {
            guess = (high + low) / 2;
            if (a[guess]  < key)
                low = guess;
            else
                high = guess;
        }
        if (high == start + len)
            return ~(start + len);
        else if (a[high] == key)
            return high;
        else
            return ~high;
    }

相應的也有SparseBooleanArray,用來取代HashMap

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章