Android中的數(shù)據(jù)結(jié)構(gòu)

什么是數(shù)據(jù)結(jié)構(gòu)?

簡(jiǎn)單說(shuō)就是以某種方式把一堆數(shù)據(jù)組織起來(lái)。通常不同的組織方式會(huì)有不同的特性坝茎。Java中常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)有:數(shù)組涤姊、鏈表、List嗤放、Map等等思喊。

為什么會(huì)有這么多數(shù)據(jù)結(jié)構(gòu)?

不同的數(shù)據(jù)結(jié)構(gòu)形式通常都有各自的使用場(chǎng)景次酌。比如常見(jiàn)的ArrayList恨课。使用ArrayList你可以方便添加和移除數(shù)據(jù)。但如果看過(guò)ArrayList源碼的話會(huì)知道ArrayList底層還是使用數(shù)組岳服。那為什么還要用ArrayList剂公?嚴(yán)格來(lái)說(shuō)Java最底層提供的數(shù)據(jù)結(jié)構(gòu)方式只有基本類型、引用類型和數(shù)組吊宋。其他任何類型都是由這些基本的數(shù)據(jù)結(jié)構(gòu)封裝起來(lái)的纲辽,或者說(shuō)其他任何Java數(shù)據(jù)結(jié)構(gòu),一層層往下拆最終都會(huì)變成這幾個(gè)璃搜。比如ArrayList就是從數(shù)組封裝過(guò)來(lái)的拖吼。那問(wèn)題來(lái)了,數(shù)組能做到这吻,那為什么還要用ArrayList吊档?主要是因?yàn)锳rrayList進(jìn)行增刪改查使用起來(lái)非常方便,但數(shù)組處理起來(lái)就要復(fù)雜多了唾糯。所以把這些常用的需求封裝起來(lái)就出現(xiàn)了ArrayList怠硼。

List

大家在使用List的時(shí)候可能通常都會(huì)寫下面這樣的代碼

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

Java中List是個(gè)接口,所以需要用它的實(shí)現(xiàn)類來(lái)實(shí)例化趾断。那當(dāng)你寫下上面代碼的時(shí)候有沒(méi)有思考過(guò)一個(gè)問(wèn)題拒名,為什么要用ArrayList。Java里有沒(méi)有其他的List實(shí)現(xiàn)類芋酌?當(dāng)然有增显。AndroidStudio或者Intelij Idea可以找到List實(shí)現(xiàn)類,然后通過(guò)Ctrl+H看到所有的繼承自List的類和接口脐帝。你可能會(huì)看到非常多同云,但比較常用的主要就是ArrayList,LinkedList和Vector堵腹。這三個(gè)都是List實(shí)現(xiàn)類炸站。有沒(méi)有想過(guò)一個(gè)問(wèn)題,如果你需要用到List了疚顷,那么究竟應(yīng)該用什么哪個(gè)類旱易?就比如你寫了一個(gè)RecyclerView的Adapter禁偎。有Adapter就一定會(huì)需要有個(gè)數(shù)據(jù)源。這時(shí)候應(yīng)該選哪個(gè)實(shí)現(xiàn)類阀坏?其實(shí)明白這三者區(qū)別就很容易選了如暖。

  • ArrayList內(nèi)部實(shí)現(xiàn)是個(gè)數(shù)組、有序存儲(chǔ)忌堂。數(shù)組大家都知道長(zhǎng)度不可變盒至,那么append數(shù)據(jù)消耗可能會(huì)比較大,因?yàn)榭赡軙?huì)需要resize士修,如果是insert或者remove數(shù)據(jù)消耗就會(huì)比較大枷遂,因?yàn)樾枰獢?shù)組拷貝。但是get速度非称宄埃快酒唉,因?yàn)榭梢灾苯诱业綄?duì)應(yīng)位置。
    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哪個(gè)寫法好沸移?remove0和remove1哪個(gè)寫法好黔州?add0一個(gè)個(gè)把數(shù)據(jù)add到ArrayList,最多ArrayList可能會(huì)發(fā)生array.length次數(shù)組resize阔籽。但是add1就最多只會(huì)發(fā)生一次數(shù)組resize。remove0和remove1也是一樣牲蜀。

  • LinkedList 看名字就知道這是一個(gè)鏈表實(shí)現(xiàn)的List笆制,內(nèi)部不再有數(shù)組。那么對(duì)于鏈表來(lái)說(shuō)添加數(shù)據(jù)就是打開(kāi)鏈條涣达,接上鏈條在辆,再鎖上鏈條的過(guò)程。如果是頻發(fā)插入數(shù)據(jù)度苔,比如數(shù)據(jù)從1條連續(xù)插入到10萬(wàn)條匆篓,效率可以認(rèn)為是一樣。但是要get數(shù)據(jù)就比較坑了寇窑,通過(guò)index并不能直接定位到數(shù)據(jù)鸦概,所以就需要遍歷數(shù)據(jù)了。remove數(shù)據(jù)也一樣甩骏,只要任何是設(shè)計(jì)到index的操作效率都會(huì)比較低窗市,除了頭和尾,因?yàn)長(zhǎng)inkedList針對(duì)頭尾做了緩存饮笛。
  • Vector 平時(shí)見(jiàn)的會(huì)非常少咨察,它內(nèi)部實(shí)現(xiàn)也是用數(shù)組,但跟ArrayList不同的是它是線程安全的福青,你會(huì)發(fā)現(xiàn)它方法有synchronized關(guān)鍵字摄狱。除了這點(diǎn)其他特性可以認(rèn)為是等同于ArrayList脓诡。

好,又回到前面老問(wèn)題媒役,RecyclerView的Adapter應(yīng)該用什么數(shù)據(jù)結(jié)構(gòu)祝谚?我們思考下Adapter的應(yīng)用場(chǎng)景。通常Adapter不會(huì)非常頻繁的添加數(shù)據(jù)刊愚,每次滑過(guò)RecyclerView都會(huì)觸發(fā)onBindViewHolder踊跟,要bind就一定需要從數(shù)據(jù)源通過(guò)index取數(shù)據(jù)出來(lái),取操作會(huì)比較頻繁鸥诽,那我們肯定不能用LinkedList了(但其實(shí)考慮到RecyclerView顯示數(shù)據(jù)都是連續(xù)的商玫,所以如果用鏈表來(lái)訪問(wèn)臨近數(shù)據(jù)效率反而會(huì)更高),又因?yàn)锳dapter基本上不會(huì)出現(xiàn)要去子線程操作數(shù)據(jù)源的情況牡借。所以也不需要線程安全拳昌。剩下的就當(dāng)然是ArrayList了,而且ArrayList取效率本來(lái)就非常高钠龙,完全符合需求炬藤。

Map

Map是一個(gè)鍵值對(duì)數(shù)據(jù)結(jié)構(gòu)。Map的實(shí)現(xiàn)類也非常多碴里,但主要是:HashMap沈矿、LinkedHashMap,TreeMap咬腋,HashTable羹膳,Android里又加了ArrayMap和SparseArray。Map跟List不一樣的是不光能存數(shù)據(jù)了根竿,還能額外多保存一個(gè)key陵像。那有個(gè)問(wèn)題,假如我新建一個(gè)下面這樣的Data類寇壳。然后把所有鍵值對(duì)通過(guò)Data對(duì)象保存到List里醒颖,那我不是一樣實(shí)現(xiàn)了鍵值對(duì)保存嗎?

   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實(shí)現(xiàn)類呢壳炎?還是同樣的問(wèn)題泞歉,雖然功能上確實(shí)能實(shí)現(xiàn)但是效率上不同的實(shí)現(xiàn)方式差別會(huì)非常大。

  • HashMap
    大家寫Map可能絕大部分情況下都是使用HashMap匿辩。HashMap底層是通過(guò)數(shù)組加鏈表(Java1.8新加了紅黑樹(shù))來(lái)實(shí)現(xiàn)疏日。為什么要搞這么復(fù)雜呢?又是數(shù)組又是鏈表又是樹(shù)的撒汉?其實(shí)還是為了提高效率沟优。上面的把鍵值對(duì)封裝成Data,加到List中睬辐。get效率跟HashMap比就會(huì)非常慘了挠阁。因?yàn)間et只能一個(gè)個(gè)去遍歷宾肺,但是HashMap就可以通過(guò)key的hashcode非常高效的get數(shù)據(jù)。
  • LinkedHashMap
    看名字就知道多了個(gè)Linked侵俗,意思就是排序锨用。LinkedHashMap本身就是繼承自HashMap,所以增刪改查方面和HashMap基本是一致的隘谣。區(qū)別主要就是通過(guò)entrySet遍歷了增拥。LinkedHashMap會(huì)保存元素的添加順序然后按順序遍歷,但HashMap就是無(wú)序了寻歧。
  • TreeMap
    TreeMap內(nèi)部是個(gè)紅黑樹(shù)掌栅。從使用角度來(lái)看,它跟LinkedHashMap主要區(qū)別就LinkedHashMap保存的是元素的插入順序码泛,而TreeMap則是對(duì)key排序猾封。遍歷可以得到一個(gè)按key排序的結(jié)果。
  • HashTable
    內(nèi)部是個(gè)鏈表噪珊,另外就是線程同步晌缘。
  • SparseArray
    SparseArray內(nèi)部依然是使用數(shù)組來(lái)實(shí)現(xiàn)。但是限制了key只能int痢站,而且沒(méi)有裝箱磷箕,HashMap的key只能是Integer。所以Sparse性能會(huì)更好阵难,它內(nèi)部做了數(shù)據(jù)壓縮搀捷,來(lái)稀疏數(shù)組的數(shù)據(jù),節(jié)省內(nèi)存多望。
  • ArrayMap
    ArrayMap內(nèi)部也是使用數(shù)組。查找數(shù)據(jù)會(huì)通過(guò)二分法來(lái)提高效率氢烘,Google推薦用ArrayMap來(lái)代替HashMap怀偷。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市播玖,隨后出現(xiàn)的幾起案子椎工,更是在濱河造成了極大的恐慌,老刑警劉巖蜀踏,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件维蒙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡果覆,警方通過(guò)查閱死者的電腦和手機(jī)颅痊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)局待,“玉大人斑响,你說(shuō)我怎么就攤上這事菱属。” “怎么了舰罚?”我有些...
    開(kāi)封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵纽门,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我营罢,道長(zhǎng)赏陵,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任饲漾,我火速辦了婚禮蝙搔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘能颁。我一直安慰自己杂瘸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布伙菊。 她就那樣靜靜地躺著败玉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪镜硕。 梳的紋絲不亂的頭發(fā)上运翼,一...
    開(kāi)封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音兴枯,去河邊找鬼血淌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛财剖,可吹牛的內(nèi)容都是我干的悠夯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼躺坟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼沦补!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起咪橙,我...
    開(kāi)封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤夕膀,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后美侦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體产舞,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年菠剩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了易猫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡具壮,死狀恐怖擦囊,靈堂內(nèi)的尸體忽然破棺而出违霞,到底是詐尸還是另有隱情,我是刑警寧澤瞬场,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布买鸽,位于F島的核電站,受9級(jí)特大地震影響贯被,放射性物質(zhì)發(fā)生泄漏眼五。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一彤灶、第九天 我趴在偏房一處隱蔽的房頂上張望看幼。 院中可真熱鬧,春花似錦幌陕、人聲如沸诵姜。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)棚唆。三九已至,卻和暖如春心例,著一層夾襖步出監(jiān)牢的瞬間宵凌,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工止后, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞎惫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓译株,卻偏偏與公主長(zhǎng)得像瓜喇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歉糜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容