性能優(yōu)化總結-數(shù)據(jù)結構優(yōu)化

? ? ?對于性能優(yōu)化朝扼,主要是從這幾個方面進行探討:數(shù)據(jù)結構,啟動速度霎肯,布局擎颖,電量和網絡,apk的大小等观游。本文從數(shù)據(jù)結構的角度進行舉例:

1.學習數(shù)據(jù)結構優(yōu)化的必要性:

? ? ?在我們開發(fā)過程中搂捧,選好一個合適的數(shù)據(jù)結構或者說一個數(shù)據(jù)容器是尤其重要的,根據(jù)其優(yōu)點懂缕,規(guī)避其缺點允跑。比如ArrayList的優(yōu)點是取元素快,但是存(這里指代替換某個元素)或者刪除則效率并不高提佣。所以當一個功能替換某個元素頻繁或者刪除某個元素頻繁時候吮蛹,則顯然不是一個好的選擇。一款app除了要有令人驚嘆的功能和令人發(fā)指的交互之外拌屏,在性能上也應該追求絲滑的要求潮针,這樣才能更好地提高用戶體驗。但是如何更好的理解或者說自己能寫出一個好的算法倚喂,則取決于我們對各個容器的特定認識每篷。并且這個東西一天兩天是講不清楚的,還需要長久的去刷題端圈,去練習焦读。這里提供一個刷題網站。-----------leetcode. ?相信每天刷幾道舱权,將會收獲很多矗晃。

本文將從這幾個點進行分析:ArrayList,LinkedList,HashMap,SparseArray,ArrayMap

首先我們從ArrayList看起:

它是一個線性數(shù)據(jù)結構,并且又是一個順序表宴倍。它的特點是:

優(yōu)點:它在物理上(內存)連續(xù),所以查找元素快张症。

缺點:刪除和增加元素需要大量移動元素仓技。增刪慢。

比如:(ArrayList內部實際上是一個數(shù)組)一個數(shù)組:int[] elementData. ? 如何能準確獲取elementData數(shù)組的第i個元素呢俗他?因為我們知道內存是連續(xù)的脖捻。elementData占四個字節(jié),假設elementData的內存地址是0xfaff456 則第i的元素為:0xfaff456+I*4.

那如何解決這個缺點呢兆衅?這里就有一個LinkedList:

LinkedList是個什么地沮?它是一個鏈表結構的容器。

優(yōu)點:空間不連續(xù)羡亩,邏輯上連續(xù),刪除增加元素快

缺點:物理上不連續(xù)摩疑,查找要輪詢。查找慢畏铆。

LinkedList是一個雙鏈表未荒,內部有一個指向下一個節(jié)點和一個指向上一個節(jié)點的指針( 如果第一個指向最后一個元素 最后一個指向第一個節(jié)點:形成了環(huán),就是環(huán)形鏈表),為什么說它刪除添加元素快呢及志?如下圖:

所以LinkedList不需要去重新移動元素(直接挪動指針)片排,從而讓添加和刪除元素性能得到提高,但是獲取元素就只能去遍歷了(內存不是連續(xù)的)速侈。

現(xiàn)在糾結一個問題率寡,有沒有一種數(shù)據(jù)結構能同時包含上面兩種優(yōu)點呢:HashMap

現(xiàn)在在面試上HashMap是面試大概率是會問的,所以在這里我們來探究一下HashMap.

HashMap是由什么構成的呢倚搬?

在1.7版本之前冶共,是由數(shù)組+鏈表構成的。

在1.8版本之后每界,是由數(shù)組+鏈表+紅黑樹組成的捅僵。

看一下HashMap是如何存放數(shù)據(jù)的:

存放:

? ? ? ? ?先計算hash的值,根據(jù)hash的值找到數(shù)組位置(下標)眨层,再往鏈表中添加元素庙楚。?

? ? ? (源碼里:h & (length-1)源碼里) == ? ??hashCode % length ?= 下標的位置: 這兩個公式其實是相等的。

? ? ? ? ?糾結:為什么源碼要用位運算,因為位運算效率是更高的趴樱。

? ? ? ? ?hash碰撞:當存入的兩個key值計算的hash是相同的馒闷,則就產生了hash碰撞,所以引入了鏈表解決hash碰撞叁征。

查找:?

? ? ? ? 先計算key的hash的值,根據(jù)hash值找到數(shù)組位置纳账,再進行遍歷數(shù)組,找到對應的元素捺疼。

刪除:

? ? ? ? ?先計算key的hash的值 ?疏虫,根據(jù)hash值找到數(shù)組位置,再從遍歷的鏈表中刪除節(jié)點。

HashMap 的擴容(請看源碼):

? ? ? ? 加載因子:Default_load_factory = 0.75;

? ? ? ? 閾值:0.75 * 16 = 12;

? ? ? ? hash 的元素大于12的時候就擴容卧秘。超過百分之75容量的時候就擴容

源碼中有一個加載因子默認是0.75尤蛮,則其閾值位0.75 * 16 = 12 ,也就是說,當HashMap的元素個數(shù)大于12的時候就進行擴容斯议,這里有一個標準,就是擴容的大小是2的次冪醇锚。

擴容的意義:(默認的hashMap的大小 == 16)

數(shù)學家研究發(fā)現(xiàn)在0.6~0.75最合適哼御,因為避免hash值總是計算相同,這樣很多元素都放在了一個鏈表中焊唬,這樣形成了單鏈表恋昼,很顯然這樣會影響性能,這樣擴容是為了避免沖突成單鏈表.

糾結一個問題赶促,擴容肯定是會影響性能的液肌。因為在擴容的時候,原本長度變了鸥滨,所以hash值就變了嗦哆,原本的元素都要重新進行計算,則就影響了性能婿滓。 那么hashMap是如何進行初始化的老速,為了節(jié)省內存,hashmap的初始化操作是在put中進行的(在用到的時候才真正初始化hash表凸主,不用的時候就不初始化了)橘券;

那么為什么HashMap是2的次冪呢?

? ? ? ?是為了這個運算 ?h& (length-1)

如果是length = 16 ?則16-1: ? ?二進制為1111

如果不是2的次冪卿吐,如果是length =?10呢旁舰? 10-1:二進制1001

現(xiàn)在有一個hash值為6 二進制為110

現(xiàn)在有一個hash值為7 二進制為111

現(xiàn)在6對length =??16求模運算: ??現(xiàn)在6對length = 10求模運算:

? 110. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?110

1111 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??1001

結果:0110 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?結果:0000

現(xiàn)在7對length =??16求模運算: ? ?現(xiàn)在7對length = 10求模運算:?

? 111 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???111

1111 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???1001

結果:0111 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?結果:?0001

可以看出:只有最高位和最低為有用,如果都是1嗡官,則四位都可以得到不一樣的值箭窜,所以更可以大的避免hash碰撞,從這個細節(jié)上來說又進行優(yōu)化了一次。

在前面可以看到我們因為只有75%的空間可以使用衍腥,但是浪費了25%绽快,我們還有什么數(shù)據(jù)結構對這個空間進行優(yōu)化了嗎?

Android量身定制:sparseArray;



sparseArray :

? ? ? ? ? ? ? ? ? ? ? 雙數(shù)組結構紧阔。 一個數(shù)組存key,一個存value坊罢。但是key值只能存放int型的數(shù)據(jù)。內部采用了二分查找的方法.

? ? 增加:

? ? ? ? ? ? ? ? ? ? ? 根據(jù)key值進行二分查找,找到可以添加元素的位置擅耽,然后插入數(shù)據(jù)并移動數(shù)據(jù)

? ? 查找:

? ? ? ? ? ? ? ? ? ? ? ?根據(jù)key值進行二分查找,找到數(shù)組下標,取出對應的value值

? ? 刪除:

? ? ? ? ? ? ? ? ? ? ? ? 根據(jù)key值進行二分查找, ?找到數(shù)組下標,?然后將value數(shù)組上的元素標記為delete活孩,并不是真的刪除,等下次再有有效的元素直接 ? ? ? ? ? ? ? ? ? ? 添加進來乖仇,不用進行移動數(shù)據(jù). ??

但是這個容器也是有缺點的因為key只能放入int型的數(shù)據(jù)憾儒。

ArrayMap: ? 任意類型的key

? ? ? hashmap + sparseMap.

這個也是有hash沖突的询兴,因為key值也要進行hash計算,當有hash沖突的時候起趾,則直接進行添加到第二個位置诗舰,比如在1的下標處有一個節(jié)點了,則直接追加到2的位置训裆。

? ? ? ?可以看到數(shù)據(jù)優(yōu)化對于我們的程序是非常重要的眶根,選擇合適的數(shù)據(jù)結構或者算法,對于程序的流暢度體驗是不一樣的边琉。但是數(shù)據(jù)結構絕不僅限此文属百,還有很多都要去學去練,我們從Arraylist一直到ArrayMap变姨,看它們的演變過程族扰,是一直在優(yōu)化的路上。所以優(yōu)化是不會停止的定欧,只有更好渔呵。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市砍鸠,隨后出現(xiàn)的幾起案子厘肮,更是在濱河造成了極大的恐慌,老刑警劉巖睦番,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件类茂,死亡現(xiàn)場離奇詭異,居然都是意外死亡托嚣,警方通過查閱死者的電腦和手機巩检,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來示启,“玉大人兢哭,你說我怎么就攤上這事》蛏ぃ” “怎么了迟螺?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長舍咖。 經常有香客問我矩父,道長,這世上最難降的妖魔是什么排霉? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任窍株,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘球订。我一直安慰自己后裸,他們只是感情好,可當我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布冒滩。 她就那樣靜靜地躺著微驶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪开睡。 梳的紋絲不亂的頭發(fā)上因苹,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天,我揣著相機與錄音士八,去河邊找鬼。 笑死梁呈,一個胖子當著我的面吹牛婚度,可吹牛的內容都是我干的。 我是一名探鬼主播官卡,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼蝗茁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了寻咒?” 一聲冷哼從身側響起哮翘,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毛秘,沒想到半個月后饭寺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡叫挟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年艰匙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抹恳。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡员凝,死狀恐怖,靈堂內的尸體忽然破棺而出奋献,到底是詐尸還是另有隱情健霹,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布瓶蚂,位于F島的核電站糖埋,受9級特大地震影響,放射性物質發(fā)生泄漏窃这。R本人自食惡果不足惜阶捆,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧洒试,春花似錦倍奢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叼架,卻和暖如春畔裕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乖订。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工扮饶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乍构。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓甜无,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哥遮。 傳聞我的和親對象是個殘疾皇子岂丘,可洞房花燭夜當晚...
    茶點故事閱讀 43,576評論 2 349