工程中选择数据结构和算法的依据
1. 時(shí)間、空間復(fù)雜度不能和性能劃等號(hào)
時(shí)間、空間復(fù)雜度不是時(shí)間執(zhí)行和內(nèi)存消耗的精確值。它們只是表示了隨著數(shù)據(jù)量的增長(zhǎng),時(shí)間、空間的增長(zhǎng)趨勢(shì)。
代碼的執(zhí)行時(shí)間有時(shí)不跟時(shí)間復(fù)雜度成正比。我們常說(shuō)算法是O(nlogn),O(n2n^2n2)這些都是基于大數(shù)據(jù)量(例如>50>50>50),在小數(shù)據(jù)量的時(shí)候可能O(n2n^2n2)比O(nlogn)更快。
對(duì)于不同問(wèn)題,不同算法之間不能做復(fù)雜度比較。復(fù)雜度只能表征不同算法在處理同類型數(shù)據(jù)、同樣問(wèn)題時(shí)候的算法 優(yōu)劣。
2. 拋開(kāi)數(shù)據(jù)規(guī)模談數(shù)據(jù)結(jié)構(gòu)和算法都是“耍流氓”
數(shù)據(jù)規(guī)模小,算法之間的優(yōu)越性體現(xiàn)不出來(lái)。
代碼執(zhí)行頻率過(guò)低,算法優(yōu)化的效果體現(xiàn)不出來(lái)。
代碼執(zhí)行頻率不高,并且是非核心代碼,選擇簡(jiǎn)單、易懂的數(shù)據(jù)結(jié)構(gòu)和算法。
流入100以內(nèi)的字符串比較用暴力匹配就挺好。使用KMP等更容易出問(wèn)題,增加維護(hù)成本。
3.結(jié)合數(shù)據(jù)特征和訪問(wèn)方式選擇數(shù)據(jù)結(jié)構(gòu)
例如Trie樹(shù)在字符串有公共前綴的情況下使用能提高搜索效率。如果數(shù)據(jù)之間都沒(méi)有公共前綴,用Trie樹(shù)就不合適了。
例如圖使用鄰接表存儲(chǔ)還是鄰接矩陣存儲(chǔ),看圖是稀疏矩陣嗎。如果是,就用鄰接表,不是就用鄰接矩陣存儲(chǔ)。
4. 區(qū)別對(duì)待 IO 密集、內(nèi)存密集和計(jì)算密集
IO密集:例如數(shù)據(jù)存儲(chǔ)在磁盤上,需要每次讀取。通過(guò)減少IO的次數(shù),提高性能 。例如數(shù)據(jù)庫(kù)查詢是IO密集型,減少數(shù)據(jù)庫(kù)操作次數(shù),提高性能。
計(jì)算密集:代碼執(zhí)行效率的瓶頸在CPU執(zhí)行上。例如已經(jīng)將數(shù)據(jù)加載到內(nèi)存中。優(yōu)化的時(shí)候要減少邏輯計(jì)算復(fù)雜度。例如用位運(yùn)算代替加減法。
內(nèi)存密集:計(jì)算操作都比較簡(jiǎn)單,代碼執(zhí)行效率的瓶頸在數(shù)據(jù)加載到內(nèi)存。例如字符串比較。因此,在選擇數(shù)據(jù)結(jié)構(gòu)和算法的時(shí)候,需要考慮是否能減少數(shù)據(jù)的讀取量,數(shù)據(jù)是否在內(nèi)存中連續(xù)存儲(chǔ),是否能利用 CPU 緩存預(yù)讀。
5.善用語(yǔ)言提供的類庫(kù),避免重復(fù)造輪子
6.有目的的優(yōu)化,不過(guò)度優(yōu)化
在有必要的時(shí)候,在核心代碼、在執(zhí)行頻率高的代碼做優(yōu)化。
我們要學(xué)會(huì)估算。估算能力實(shí)際上也是一個(gè)非常重要的能力。我們不僅要對(duì)普通情況下的數(shù)據(jù)規(guī)模和性能壓力做估算,還需要對(duì)異常以及將來(lái)一段時(shí)間內(nèi),可能達(dá)到的數(shù)據(jù)規(guī)模和性能壓力做估算。這樣,我們才能做到未雨綢繆,寫出來(lái)的代碼才能經(jīng)久可用。
當(dāng)真的要優(yōu)化代碼的時(shí)候,一定要先做 Benchmark 基準(zhǔn)測(cè)試。這樣才能避免你想當(dāng)然地?fù)Q了一個(gè)更高效的算法,但真實(shí)情況下,性能反倒下降了。
總結(jié)
以上是生活随笔為你收集整理的工程中选择数据结构和算法的依据的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 九九乘法表的C语言实现
- 下一篇: 总和最大区间问题