資料結構-堆和堆排序
是什麼
堆是二叉樹。不是物件記憶體的堆。不同的概念。
本質是一個資料結構,二叉樹。有一些特點的二叉樹。
基於陣列實現。
堆的特點
1.完全二叉樹 //即只有葉子那一層,允許有空節點
2.父節點比子節點大 //弱序 正因為父節點比子節點大,基於這個,根節點始終是最大的節點。
示意圖
弱序
父節點,比子節點要大。但是又不是有序二叉樹。
弱序的結果
1.彈出資料
就是隻有隊頭才是最大的,權重最高,在最上面。每次彈出資料,就是從頂點彈出。
2.排序 //當然是弱序 也就是排序完成之後,仍然是根節點才是最大的。
怎麼排序?
1.刪除一個節點 //插入根節點
2.插入節點 //插入陣列最後一個節點到陣列第一個節點(也是根節點)
把最後一個節點(即陣列的最後一個節點,也是二叉樹的最後一個節點),插入到根節點(因為根節點,是空節點)
3.排序
就是拿根節點和下面的資料進行排序,一直到最合適的位置為止
插入新的資料
1.插入到陣列的最後一個節點
2.排序
拿新的節點,向上排序
弱序要解決的問題,即應用場景
步驟
1.每次只刪除根節點
2.刪除之後,重新排序
3.如果是插入新的資料,也要重新排序
解決的問題
永遠是刪除根節點的資料 //即每次是刪除根節點
應用場景
比如書裡面提到的,1.讀信的時候,根據優先順序來讀信2.作業系統時間片輪詢程式,也是根據程式的優先順序。
也就是說,只要是有優先順序/權重的需求,都適合。
比如,dubbo服務的權重。
作用-堆排序?
具體怎麼排?
1.插入資料的時候,弱序。//迴圈插入所有資料。結果是弱序。
2.刪除資料 //每次刪除資料,都是最大資料。這樣就可以得到top N。
速度
n * logN //n是外層迴圈。logN是每次插入或刪除資料的時候,要二分查詢樹。
那他和快排有什麼區別呢?
快排也是logN。優勢在哪裡?
其他應用場景
圖查詢
檔案壓縮演演算法
比快排的優點是什麼?
學他,是因為有優點。否則,不學。
優點
穩定性更高。//穩定性,指的是,最好和最壞情況,速度差不多。
因為堆排序是n * logN //第一個n是n個資料。第二個logN,是因為基於樹的二分操作。
快排,也是n * logN //第一個也是n。第二個是logN,基於二分/劃分思想,不斷的遞迴呼叫。
既然速度都一樣,那區別到底在哪裡?剛才說了,在穩定性。
為什麼會有穩定性的區別呢?
區別在於,堆排序的初始資料,是自己手動插入的。所以不可能是最壞情況。
而,快排的初始資料是準備好的。可能是倒序。這樣就相當於惡化為n * n。
總結
優點肯定還是兩個方面:
1.速度
2.空間
但是速度有不同的方面,可以進行優化。
空間也是。
為什麼海量資料,就一定要使用堆排序?
其他的演演算法,都是直接在記憶體排序的。所以,資料量不能很多,因為記憶體大小有限。那怎麼辦?只能使用很小的記憶體,來排序海量資料。
比如,
10~3 = 1K
10~6 = 1M //百萬級別資料
10~9 = 1G //十億級別。這就是為什麼top k問題,都是說10億級別的資料,怎麼排序?就是因為十億級別的資料,記憶體已經放不下了。
解決方法
堆排序 //一次只從資料來源(比如,資料庫)讀少量資料,然後找top K。比如top 10。
那麼怎麼辦?就是隻需要10個資料的記憶體,每次讀的少量資料,每次即每個資料插入到堆資料結構的時候,做到兩點1.插入資料2.根節點最小。//好,現在第一步,我們已經插入了10個資料到堆資料結構。
接下來,插入第11個資料,怎麼辦?和隊頭的資料比較,如果小,就丟棄。如果大,就插入新的資料,怎麼插入?1.彈出當前根節點,即隊頭資料2.插入新的資料3.向下二分查詢,把最小資料,移到跟節點,即隊頭。
就這樣,一直到最後一個資料,那麼最終堆資料結構裡的資料,就是top K。
向上和向下
插入資料的時候,或者刪除資料的時候,都需要重新排序。怎麼排序?向上二分查詢,或者向下二分查詢。
向下
每次比較子資料,子資料有兩個,所以比較兩次。如果都比父資料大,那麼還要比較兩個子資料哪個大,哪個大就和哪個資料交換。
向上
只需要和父資料,比較一次。
堆的本質
堆可以被用來排序,但作用不僅僅是排序。
他本質的作用是,優先順序。最高優先順序的資料,先被處理。
優先順序佇列
二叉樹堆的底層是優先順序佇列,也就是說,本質是優先順序佇列。
什麼是優先順序佇列?
佇列是先進後出。優先順序佇列,在先進後出的基礎之上,還多了一個特性:那就是資料有序。
比如,1 2 3 ... 10 //1是隊頭,10是尾。1先出去。
有序
1.完全有序 //有序二叉樹
2.弱序 //比如堆,只要求父節點比子節點大
本質
優先順序的本質,就是有序。有順序。這個順序,可以是完全有序,也可以是弱序。
資料結構
用什麼資料結構實現?
1.陣列 //有序
2.堆 //二叉樹。底層也還是仍然基於陣列實現二叉樹。
參考
java資料結構和演演算法 //非常好的一本書。淺顯易懂。我認為是最好的一本資料結構和演演算法的書。作者已經死了。