Android中的數據結構

什么是數據結構?

簡單說就是以某種方式把一堆數據組織起來。通常不同的組織方式會有不同的特性。Java中常見的數據結構有:數組、鏈表、List、Map等等。

為什么會有這么多數據結構?

不同的數據結構形式通常都有各自的使用場景。比如常見的ArrayList。使用ArrayList你可以方便添加和移除數據。但如果看過ArrayList源碼的話會知道ArrayList底層還是使用數組。那為什么還要用ArrayList?嚴格來說Java最底層提供的數據結構方式只有基本類型、引用類型和數組。其他任何類型都是由這些基本的數據結構封裝起來的,或者說其他任何Java數據結構,一層層往下拆最終都會變成這幾個。比如ArrayList就是從數組封裝過來的。那問題來了,數組能做到,那為什么還要用ArrayList?主要是因為ArrayList進行增刪改查使用起來非常方便,但數組處理起來就要復雜多了。所以把這些常用的需求封裝起來就出現了ArrayList。

List

大家在使用List的時候可能通常都會寫下面這樣的代碼

List<String> list = new ArrayList<>();

Java中List是個接口,所以需要用它的實現類來實例化。那當你寫下上面代碼的時候有沒有思考過一個問題,為什么要用ArrayList。Java里有沒有其他的List實現類?當然有。AndroidStudio或者Intelij Idea可以找到List實現類,然后通過Ctrl+H看到所有的繼承自List的類和接口。你可能會看到非常多,但比較常用的主要就是ArrayList,LinkedList和Vector。這三個都是List實現類。有沒有想過一個問題,如果你需要用到List了,那么究竟應該用什么哪個類?就比如你寫了一個RecyclerView的Adapter。有Adapter就一定會需要有個數據源。這時候應該選哪個實現類?其實明白這三者區別就很容易選了。

  • ArrayList內部實現是個數組、有序存儲。數組大家都知道長度不可變,那么append數據消耗可能會比較大,因為可能會需要resize,如果是insert或者remove數據消耗就會比較大,因為需要數組拷貝。但是get速度非常快,因為可以直接找到對應位置。
    private static List<String> add0(String[] array) {
        List<String> list = new ArrayList<>();
        for (String s : array) {
            list.add(s);
        }
        return list;
    }
    private static List<String> add1(String[] array) {
        List<String> list = new ArrayList<>();
        list.addAll(Arrays.asList(array));
        return list;
    }

    private static void remove0(List<String> list, int index, int count) {
        for (int i = 0; i < count; i++) {
            list.remove(index + i);
        }
    }

    private static void remove1(List<String> list, int index, int count) {
        list.subList(index, index + count).clear();
    }

add0和add1哪個寫法好?remove0和remove1哪個寫法好?add0一個個把數據add到ArrayList,最多ArrayList可能會發生array.length次數組resize。但是add1就最多只會發生一次數組resize。remove0和remove1也是一樣。

  • LinkedList 看名字就知道這是一個鏈表實現的List,內部不再有數組。那么對于鏈表來說添加數據就是打開鏈條,接上鏈條,再鎖上鏈條的過程。如果是頻發插入數據,比如數據從1條連續插入到10萬條,效率可以認為是一樣。但是要get數據就比較坑了,通過index并不能直接定位到數據,所以就需要遍歷數據了。remove數據也一樣,只要任何是設計到index的操作效率都會比較低,除了頭和尾,因為LinkedList針對頭尾做了緩存。
  • Vector 平時見的會非常少,它內部實現也是用數組,但跟ArrayList不同的是它是線程安全的,你會發現它方法有synchronized關鍵字。除了這點其他特性可以認為是等同于ArrayList。

好,又回到前面老問題,RecyclerView的Adapter應該用什么數據結構?我們思考下Adapter的應用場景。通常Adapter不會非常頻繁的添加數據,每次滑過RecyclerView都會觸發onBindViewHolder,要bind就一定需要從數據源通過index取數據出來,取操作會比較頻繁,那我們肯定不能用LinkedList了(但其實考慮到RecyclerView顯示數據都是連續的,所以如果用鏈表來訪問臨近數據效率反而會更高),又因為Adapter基本上不會出現要去子線程操作數據源的情況。所以也不需要線程安全。剩下的就當然是ArrayList了,而且ArrayList取效率本來就非常高,完全符合需求。

Map

Map是一個鍵值對數據結構。Map的實現類也非常多,但主要是:HashMap、LinkedHashMap,TreeMap,HashTable,Android里又加了ArrayMap和SparseArray。Map跟List不一樣的是不光能存數據了,還能額外多保存一個key。那有個問題,假如我新建一個下面這樣的Data類。然后把所有鍵值對通過Data對象保存到List里,那我不是一樣實現了鍵值對保存嗎?

   public class Data<K,V>{
        private K mKey;
        private V mValue;

        public Data(K key, V value) {
            mKey = key;
            mValue = value;
        }

        public K getKey() {
            return mKey;
        }

        public void setKey(K key) {
            mKey = key;
        }

        public V getValue() {
            return mValue;
        }

        public void setValue(V value) {
            mValue = value;
        }
    }

那我為什么要用各種Map實現類呢?還是同樣的問題,雖然功能上確實能實現但是效率上不同的實現方式差別會非常大。

  • HashMap
    大家寫Map可能絕大部分情況下都是使用HashMap。HashMap底層是通過數組加鏈表(Java1.8新加了紅黑樹)來實現。為什么要搞這么復雜呢?又是數組又是鏈表又是樹的?其實還是為了提高效率。上面的把鍵值對封裝成Data,加到List中。get效率跟HashMap比就會非常慘了。因為get只能一個個去遍歷,但是HashMap就可以通過key的hashcode非常高效的get數據。
  • LinkedHashMap
    看名字就知道多了個Linked,意思就是排序。LinkedHashMap本身就是繼承自HashMap,所以增刪改查方面和HashMap基本是一致的。區別主要就是通過entrySet遍歷了。LinkedHashMap會保存元素的添加順序然后按順序遍歷,但HashMap就是無序了。
  • TreeMap
    TreeMap內部是個紅黑樹。從使用角度來看,它跟LinkedHashMap主要區別就LinkedHashMap保存的是元素的插入順序,而TreeMap則是對key排序。遍歷可以得到一個按key排序的結果。
  • HashTable
    內部是個鏈表,另外就是線程同步。
  • SparseArray
    SparseArray內部依然是使用數組來實現。但是限制了key只能int,而且沒有裝箱,HashMap的key只能是Integer。所以Sparse性能會更好,它內部做了數據壓縮,來稀疏數組的數據,節省內存。
  • ArrayMap
    ArrayMap內部也是使用數組。查找數據會通過二分法來提高效率,Google推薦用ArrayMap來代替HashMap。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評論 6 545
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,795評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,773評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,106評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,282評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,793評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,507評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,741評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,929評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,482評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,702評論 2 380

推薦閱讀更多精彩內容