????1哈希算法(上)
? ? ? ? 將任意長(zhǎng)度的二進(jìn)制值串映射為固定長(zhǎng)度的二進(jìn)制值串,這個(gè)映射的規(guī)則就是哈希算法。通過原始數(shù)據(jù)映射之后得到的二進(jìn)制值串就是哈希值。
? ? ? ? 如:
? ? ? ? 這節(jié)課的內(nèi)容比較偏實(shí)戰(zhàn),了解了哈希算法的四個(gè)應(yīng)用場(chǎng)景,分別是:
? ? ? ? 1.安全加密。我們講到任何哈希算法都會(huì)出現(xiàn)散列沖突,但是這個(gè)沖突概率非常小。越是復(fù)雜的哈希算法越難破解,但是同樣的它的計(jì)算時(shí)間也會(huì)比較長(zhǎng)。所以選擇哈希算法的時(shí)候,要權(quán)衡一下安全性和計(jì)算時(shí)間來決定使用哪種哈希算法。
? ? ? ? 2.唯一標(biāo)識(shí)。哈希算法可以對(duì)大數(shù)據(jù)做信息摘要,通過一個(gè)較短的二進(jìn)制編碼來表示很大的數(shù)據(jù)。
? ? ? ? 3.數(shù)據(jù)校驗(yàn)。用于校驗(yàn)數(shù)據(jù)的完整性和正確性。
? ? ? ? 4.散列函數(shù)。我們前面講的散列函數(shù)也是哈希算法的一種應(yīng)用,它對(duì)哈希算法的要求非常特別,更加看重的是散列的平均性和哈希算法的執(zhí)行效率。
? ? 2哈希算法(下)
? ? ? ? 上節(jié)課講了哈希算法的四個(gè)應(yīng)用,這節(jié)課再補(bǔ)充三個(gè)應(yīng)用,但是它們和上節(jié)課的應(yīng)用稍稍有些不同,因?yàn)檫@節(jié)課的三個(gè)應(yīng)用都和分布式系統(tǒng)有關(guān)。
? ? ? ? 5.負(fù)載均衡。通過哈希算法,對(duì)客戶端IP地址或者會(huì)話ID計(jì)算哈希值,將取得的哈希值與服務(wù)器列表的大小進(jìn)行進(jìn)行取模運(yùn)算,最終得到的值就是應(yīng)該被路由到的服務(wù)器編號(hào)。
????????利用哈希算法替代映射表,可以實(shí)現(xiàn)一個(gè)會(huì)話粘滯的負(fù)載均衡策略。
? ? ? ? (會(huì)話粘滯我理解為同一個(gè)客戶端請(qǐng)求服務(wù)時(shí)都路由到同一個(gè)服務(wù)器上)
? ? ? ? 6.數(shù)據(jù)分片。
? ? ? ? 數(shù)據(jù)分片這里舉了兩個(gè)例子,一個(gè)是統(tǒng)計(jì)“搜索關(guān)鍵詞”出現(xiàn)的次數(shù):我們可以先對(duì)數(shù)據(jù)進(jìn)行分片,然后采用多臺(tái)機(jī)器處理的方法,來提高處理速度;另一個(gè)是快速判斷圖片是否在庫(kù)中:通過哈希算法計(jì)算這個(gè)圖片的唯一標(biāo)識(shí),然后與機(jī)器個(gè)數(shù)n求余取模,得到對(duì)應(yīng)的機(jī)器編號(hào)。
????????通過哈希算法對(duì)處理的海量數(shù)據(jù)進(jìn)行分片,多機(jī)分布式處理,可以突破單機(jī)資源的限制。
? ? ? ? 7.分布式存儲(chǔ)。現(xiàn)在互聯(lián)網(wǎng)面對(duì)的都是海量的數(shù)據(jù)、海量的用戶,我們?yōu)榱颂岣邤?shù)據(jù)的讀取、寫入能力,一般都采用分布式的方式來存儲(chǔ)數(shù)據(jù)。和前面的思想一樣,通過哈希算法對(duì)數(shù)據(jù)取哈希值,然后對(duì)機(jī)器個(gè)數(shù)取模,這個(gè)最終值就是應(yīng)該存儲(chǔ)的緩存機(jī)器編號(hào)。
? ? ? ? ?但是此時(shí)出現(xiàn)了一個(gè)問題,如果數(shù)據(jù)增多到原先的10個(gè)(假如它是10個(gè))已經(jīng)無法承受了,我們就需要擴(kuò)容,比如擴(kuò)到11個(gè)機(jī)器,那么現(xiàn)在哈希值與機(jī)器個(gè)數(shù)取模得到的結(jié)果和之前計(jì)算的結(jié)果就不一致了。
? ? ? ? 這里引入了一致性哈希算法:假如我們有k個(gè)機(jī)器,數(shù)據(jù)的哈希值的范圍是[0,MAX]。我們將整個(gè)范圍劃分成m個(gè)小區(qū)間(m遠(yuǎn)大于k),每個(gè)機(jī)器負(fù)責(zé)m/k個(gè)小區(qū)間。當(dāng)有新機(jī)器加入的時(shí)候,我們就將某幾個(gè)小區(qū)間的數(shù)據(jù),從原來的機(jī)器中搬移到新的機(jī)器中。這樣,既不用全部重新哈希、搬移數(shù)據(jù),也保持了各個(gè)機(jī)器上數(shù)據(jù)數(shù)量的均衡。
? ? ? ? 利用一致性哈希算法,可以解決緩存等分布式系統(tǒng)的擴(kuò)容、縮容導(dǎo)致的數(shù)據(jù)大量搬移的難題。
? ? 3二叉樹(上)
????????前面我們學(xué)習(xí)的都是線性表結(jié)構(gòu),棧、隊(duì)列等等。今天我們學(xué)習(xí)一種非線性表結(jié)構(gòu)——樹。
? ? ? ? 話不多說,看圖:
????????注意弄清楚樹中的父節(jié)點(diǎn)、子節(jié)點(diǎn)、兄弟節(jié)點(diǎn)、葉節(jié)點(diǎn)的概念。
? ? ? ? 另外幾個(gè)比較重要的概念就是高度(Height)、深度(Depth)、層(Level),注意不要弄混哦:
? ? ? ? 可以參考下面這張圖更好的理解它們?nèi)齻€(gè)的不同:
? ? ? ? 樹的結(jié)構(gòu)很多樣,但我們最常用的還是二叉樹:每個(gè)節(jié)點(diǎn)最多有兩個(gè)子節(jié)點(diǎn),分別是左子節(jié)點(diǎn)和右子節(jié)點(diǎn)。(但是并不要求每個(gè)節(jié)點(diǎn)都必須有兩個(gè)子節(jié)點(diǎn)哦)
? ? ? ? 注意有兩種比較特殊的二叉樹。
? ? ? ? 1.滿二叉樹。即上圖中的編號(hào)為2的二叉樹。
? ? ? ? 2.完全二叉樹。即上圖中的編號(hào)為3的二叉樹。注意區(qū)分完全二叉樹和非完全二叉樹哦,這個(gè)比較容易弄混。其實(shí)滿二叉樹就是完全二叉樹的一種特殊形式。
? ? ? ? 想要存儲(chǔ)一顆二叉樹,有兩種辦法:1.基于指針或者引用的二叉鏈?zhǔn)酱鎯?chǔ)法,2.基于數(shù)組的順序存儲(chǔ)法。
? ? ? ? 鏈?zhǔn)酱鎯?chǔ)法:
? ? ? ? 順序存儲(chǔ)法:
? ? ? ? 重點(diǎn)理解一下順序存儲(chǔ)法,完全二叉樹就是因?yàn)轫樞虼鎯?chǔ)法而被引出,它在存儲(chǔ)完全二叉樹的時(shí)候非常節(jié)省空間。
? ? ? ? 二叉樹的遍歷方式有:前序遍歷、中序遍歷、后續(xù)遍歷,注意它們的不同:
? ? ? ? 這三種遍歷方式都是通過遞歸實(shí)現(xiàn)哦,并且遍歷的復(fù)雜度都為O(n)。
? ? 4二叉樹(下)
? ? ? ? 這節(jié)課學(xué)習(xí)了一種特殊的二叉樹,二叉查找樹,它支持快速地查找、插入、刪除操作。(要掌握這三種操作的實(shí)現(xiàn)方式哦)
? ? ? ? 二叉查找樹中,每個(gè)節(jié)點(diǎn)的值都大于左子樹節(jié)點(diǎn)的值,小于右子樹節(jié)點(diǎn)的值。不過,這只是針對(duì)沒有重復(fù)數(shù)的情況。
? ? ? ? 對(duì)于存在重復(fù)數(shù)據(jù)的二叉查找樹,有兩種解決方法:1.讓每個(gè)節(jié)點(diǎn)存儲(chǔ)多個(gè)值相同的數(shù)據(jù),2.每個(gè)節(jié)點(diǎn)中存儲(chǔ)一個(gè)數(shù)據(jù),將值相同的數(shù)據(jù)存儲(chǔ)在它的右子樹中。
? ? ? ? 在二叉查找樹中,查找、插入、刪除等很多操作的時(shí)間復(fù)雜度都跟樹的高度成正比,兩個(gè)極端情況的時(shí)間復(fù)雜度分別是O(n)和O(logn),分別對(duì)應(yīng)二叉樹退化成鏈表的情況和完全二叉樹。
? ? ? ? 為了避免時(shí)間復(fù)雜度的退化,針對(duì)二叉查找樹,又設(shè)計(jì)了一種更加復(fù)雜的樹——平衡二叉查找樹,時(shí)間復(fù)雜度可以做到穩(wěn)定的O(logn),這就是我們下節(jié)課的內(nèi)容啦~
? ? ? ? 另外有一點(diǎn)要注意的是,為什么有的時(shí)候會(huì)用平衡二叉查找樹而不是用散列表,也就是平衡二叉查找樹相對(duì)散列表的優(yōu)勢(shì)(當(dāng)然散列表也是有自己優(yōu)勢(shì)噠,它們各自都有自己的閃光點(diǎn)~)。
? ? 5紅黑樹(上)
? ? ? ? 平衡二叉樹:二叉樹中任意一個(gè)節(jié)點(diǎn)的左右子樹的高度相差不能大于1。(這樣說來其實(shí)我們之前說的滿二叉樹、完全二叉樹都是平衡二叉樹。但是非完全二叉樹也有可能是平衡二叉樹哦~)
? ? ? ? 平衡二叉查找樹:同時(shí)滿足平衡二叉樹和二叉查找樹的特點(diǎn)。
? ? ? ? 紅黑樹(R-B Tree):樹中的節(jié)點(diǎn)一類被標(biāo)記為黑色,一類被標(biāo)記為紅色,除此之外還有幾個(gè)需要滿足的小條件,此處略。
? ? ? ? 紅黑樹是“近似平衡”的,它做到了性能不會(huì)退化的太嚴(yán)重。其實(shí)紅黑樹并不是嚴(yán)格意義上的平衡查找二叉樹,它沒有完全符合左右子樹相差不能大于1這個(gè)條件,但是我們把“平衡”理解為時(shí)間復(fù)雜度退化不要太嚴(yán)重的時(shí)候,它依然是一棵合格的平衡二叉查找樹。紅黑樹的高度接近logn,所以它是近似平衡,插入、刪除、查找操作的時(shí)間復(fù)雜度都是O(logn)。
? ? ? ? 紅黑樹的實(shí)現(xiàn)很難。但我們其實(shí)不應(yīng)該把重點(diǎn)放在它的實(shí)現(xiàn)上。我們學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)和算法,要學(xué)習(xí)它的由來、特性、適用的場(chǎng)景以及它能解決的問題。
????????因?yàn)榧t黑樹是一種性能非常穩(wěn)定的二叉查找樹,所以在工程中,但凡是用到動(dòng)態(tài)插入、刪除、查找數(shù)據(jù)的場(chǎng)景,都可以用到它。
? ? ? ? 但它實(shí)現(xiàn)起來比較難,如果要自己寫代碼來實(shí)現(xiàn),我們更傾向于用跳表來代替它。
? ? ? ? 另外注意要知道,為什么工程中都喜歡用紅黑樹,而不是其他平衡二叉查找樹(如Treap、Splay Tree、AVL數(shù)等)呢?
? ? 6紅黑樹(下)
? ? ? ? 這節(jié)課講了紅黑樹的實(shí)現(xiàn)方法,其實(shí)我有偷懶沒有認(rèn)真去看它的細(xì)節(jié),因?yàn)槟壳皝碚f我不太需要掌握這些細(xì)節(jié),畢竟面試官也不會(huì)考我手寫紅黑樹的代碼,哈哈~當(dāng)然如果我真的需要去實(shí)現(xiàn)的時(shí)候,就需要跟著這些步驟把每個(gè)細(xì)節(jié)搞清楚然后一步一步去實(shí)現(xiàn)。
? ? ? ? 上節(jié)課有說紅黑樹的定義,它還有一些小的要求,我當(dāng)時(shí)沒有寫出來,現(xiàn)在寫出來看一看:
? ? ? ? 1.根節(jié)點(diǎn)是黑色的;
? ? ? ? 2.每個(gè)葉子節(jié)點(diǎn)都是黑色的空節(jié)點(diǎn)(NIL),也就是說,葉子節(jié)點(diǎn)不存儲(chǔ)數(shù)據(jù);
? ? ? ? 3.任何相鄰的節(jié)點(diǎn)都不能同時(shí)為紅色,也就是說,紅色節(jié)點(diǎn)是被黑色節(jié)點(diǎn)隔開的;
? ? ? ? 4.每個(gè)節(jié)點(diǎn),從該節(jié)點(diǎn)到達(dá)其可達(dá)子節(jié)點(diǎn)的所有路徑,都包含相同數(shù)目的黑色節(jié)點(diǎn)。
? ? ? ? 而在插入、刪除節(jié)點(diǎn)的過程中,第三、第四點(diǎn)要求可能會(huì)被破壞,而我們?cè)趯?shí)現(xiàn)紅黑樹的時(shí)候,關(guān)鍵點(diǎn)就在于在插入和刪除的過程中進(jìn)行“平衡調(diào)整”,實(shí)際上就是要把被破壞的第三、四點(diǎn)恢復(fù)過來。
? ? ? ? 在這個(gè)過程中需要用到的操作有:左旋(rotate left)、右旋(rotate right)、改變顏色,左旋右旋有它們的定義,這里不作贅述。正在處理的節(jié)點(diǎn)叫做關(guān)注節(jié)點(diǎn)。
? ? ? ? 如果需要實(shí)現(xiàn),我們可以跟著步驟一步一步來做,需要注意以下三點(diǎn):
? ? ? ? 1.把紅黑樹的平衡調(diào)整的過程比作魔方復(fù)原,不要過于深究這個(gè)算法的正確性,只要按照固定的操作步驟進(jìn)行就OK了。
? ? ? ? 2.找準(zhǔn)關(guān)注節(jié)點(diǎn),不要搞丟、搞錯(cuò)關(guān)注節(jié)點(diǎn)。
? ? ? ? 3.插入操作的平衡調(diào)整比較簡(jiǎn)單,但是刪除操作就比較復(fù)雜。
? ??????