最近讀了一篇好文:【微信高併發資金交易系統設計方案——百億紅包背後的技術支撐】,其中關於高併發性能問題的解決方案中,有應用 hash 算法的思想。想起公衆號後臺裏斷斷續續有讀者提起算法方面的問題,以爲能夠寫篇文章聊聊算法中的 hash 算法。順道科普下算法與數據結構的重要性。程序員
開講前,先跑題閒聊下程序員的技術功底。我常說每一個程序員都有本身獨特的技術視野和知識盲區,不一樣程序員之間很難由於某些知識點儲備不同而分個高低好壞。但咱們工做當中,又能明顯感受不一樣團隊成員之間的技術水平存在差別,到底差在哪呢?不少人調侃批量生產的培訓程序員,那這些人和四年的大學本科之間又有多少距離?僅僅是時間嗎?面試
差在基本功,基本功有不少項,數據結構與算法就是其中之一。雖然是基本功,倒是最難儲備和最易忽視的。行業越浮躁,變化越快,開發平臺越便捷,高級 API 越多,基本功的重要性就越容易被忽視。即便能意識到基礎薄弱,肯下定決心騰出幾個月時間惡補基本功不是件容易的事,尤爲是參加工做後,雜事繁多,一時熱血下定的決心能堅持一週都屬不易。後臺偶爾有人問及程序員如何進階的問題,以我這些年所經驗,回過頭來夯實下基礎,對大部分人都會有奇效。算法
數據結構與算法的學習難度常常被誇大,很多人甚至談算法色變,尤爲沒法忍受在面試當中問及算法問題。其實多點兒耐心,多投入些時間,學習算法並不難。至少學習基礎的算法並不難,理解算法和去 leetcode 刷題是兩回事,刷題所涉及的算法多須要技巧,基礎的算法知識和其餘計算機知識同樣,不須要特別「聰明」的大腦,大多數人都能學會。Peak 君沒刷過題,但對算法方面的知識也比較有自信。編程
數據結構和算法是相輔相成的,基礎的其實就那麼些:時間複雜度的概念,List,Array,Stack,Queue,Tree 等。Graph 實際應用中較少遇到,能夠不作深刻了解,但 BFS,DFS,Dijkstra 仍是應該知道。基礎的算法須要能達到手寫的程度,好比排序至少能寫出兩種時間複雜度爲 N*logN 的算法。理解這些比去 leetcode 刷題重要,學習難度也並不高。學習這些的意義在於掌握解決問題的基礎思路,造成計算機思惟,好比 divide and conque,recursive 等常規思想。服務器
再回到本文重點 hash 算法。關於 hash 算法的實現原理和關鍵概念,網絡上已有很多好文加以介紹。本文不作原理層面的解釋,只談應用。對實現感興趣的能夠搜索關鍵字:hash,load factor,擴容,hash 衝突解決等。微信
Objective C 中對於 hash 的應用主要封裝在兩個數據類當中:NSDictionary 和 NSSet。這點你們都知道,hash 算法能以空間換時間,在 NSDictionary 和 NSSet 中,判斷一個元素是否存在只須要 O(1) 的時間複雜度。這一特色也使得在一些須要快速存取元素的場景,好比 Cache 設計,也能看到 NSDictionary 的身影。固然 hash 的應用遠不止如此,作的應用越多,解決問題越深刻,碰到 hash 算法的機率也會更高。網絡
「The Algorithm Design Manual」一書中提到,雅虎的 Chief Scientist ,Udi Manber 曾說過,在 yahoo 所應用的算法中,最重要的三個是:hash,hash 和 hash。其重要性不言而喻。書中還舉了一個頗有趣的應用例子,請聽題:數據結構
一場拍賣會中,物品是價高者得,若是每一個人只有一次出價機會,同時提交本身的價格後,最後一塊兒公佈,出價最高則勝出。這種形式存在做弊的可能,若是有出價者能 hack 進後臺,而後將本身的價格改成最高價 + 1,則能以最低的代價得到勝利。如何杜絕這種做弊呢?多線程
三分鐘思考時間,一,二,三。併發
參與者都提交自身出價的 hash 值就能夠了,即便有人能黑進後臺也沒法得知明文價格,等到公佈之時,再對比原出價與 hash 值是否對應便可。是否是很巧妙?
看到這,可能有朋友想到了 MD5,SHA。是的,上面的作法,和咱們在 server 端存儲密碼的 MD5 值而非明文,是同一種思想,異曲同工。hash 算法包含有多種解決問題的思路,這裏能夠概括爲【經過 hash,生成不可逆的信息摘要】。
書裏還有關於 hash 應用的其餘有趣的場景(好比論文內容抄襲檢測),都值得一讀。
回到微信紅包的例子,後臺工程師爲了防止搶紅包時,用戶的流量都涌進同個服務器,在同個 DB 上讀寫而致使的性能降低,採用了經過 hash 算法來分流的策略。每一個紅包建立的時候分配一個 ID,經過算法將 ID 映射到不一樣的邏輯服務器,一鼓作氣的解決方案。這裏體現的是 hash 算法的另外一種思想:【hash 能以 O(1)的複雜度將內容映射到位置】。這種應用 hash 的思路很是常見,還有很多例子。
去年寫過一篇多線程文章【正確使用多線程同步鎖@synchronized()】,當時閱讀 OC 源碼的時候也看到了 hash 的身影。@synchronized(token) 中的 token 經過 hash 算法存儲到了一份手動維護的 cache 中,cache 的 key 使用的是 token 的內存地址。@synchronized 使用多了以後,如何快速的經過 token 取出對應的鎖,對多線程的性能相當重要。hash 算法恰能以 O(1)的時間複雜度,以 token 爲 key 取出對應的鎖,和上面紅包的例子本質上是同一種思想。即內容與位置之間的快速映射關係。
我還見到過不少例子,多多少少都有 hash 算法的影子。你們說 hash 算法是否是很重要?數據結構與算法是否是要學?不懂算法,有時候看別人代碼就真如「過眼雲煙」了,觀其形而不知其意。別人賞雪,心中所念是:「都城十日雪,庭戶皓已盈」,你只能一句「我靠!好美!」以抒胸臆,豈不煞風景?
以前有幾位讀者在後臺留言,求算法書推薦。算法方面的好書有很多,不過大可能是英文的,除去一些專業術語外,可能是一些簡單的詞彙,閱讀難度不算大,維堅持二字。推薦一本現今還留有印象的:《編程珠璣》,英文名《Programming Pearls》,不是大部頭,建議啃英文原版。
最近有些忙了,不過至少仍是會堅持一週一到兩篇,和你們分享些技術心得和職場感悟。堅持作一件事不容易,寫公衆號這事,怎麼都得挺住。寫年終總結時,就多了件能夠吹噓的事 :)
歡迎關注公衆號:MrPeakTech