topK算法,簡而言之,就是求n個數據裏的前m大個數據,通常而言,m<<n,也就是說,n可能有幾千萬,而m只是10或者20這樣的兩位數。php
最簡單的思路,固然是使用要先對這n個數據進行排序,由於只有排序之後,才能按照順序來找出排在前面的,或者排在後面的數據。算法
假如說咱們用快拍,那麼時間複雜度是O(nlogn),可是仔細看題目,會發現實際上不要要將全部的數據就進行排序,由於咱們找的是前m個數據,因此對全部數據排序實際上有些浪費了。因此能夠想到,只維護一個大小爲m的數組,而後掃一遍原來的數組n,只將大於數組m裏的最小值的數據插入到m數組裏,而且從新調整m數組的順序。數組
若是使用樸素的方法對m數組進行調整,那麼時間複雜度將會是O(n*m),這顯然不是最優的結果。對於維護的數組m,咱們能夠經過維護一個堆結構,來達到每次排序O(logm)的時間複雜度,這樣topK算法,整體的複雜度也就變成了O(nlogm)。this
二叉堆是徹底二叉樹或者是近似徹底二叉樹。spa
二叉堆知足二個特性:3d
1.父結點的鍵值老是大於或等於(小於或等於)任何一個子節點的鍵值。code
2.每一個結點的左子樹和右子樹都是一個二叉堆(都是最大堆或最小堆)。blog
當父結點的鍵值老是大於或等於任何一個子節點的鍵值時爲最大堆。當父結點的鍵值老是小於或等於任何一個子節點的鍵值時爲最小堆。下圖展現一個最小堆:通常都用數組來表示堆,i結點的父結點下標就爲(i – 1) / 2。它的左右子結點下標分別爲2 * i + 1和2 * i + 2。如第0個結點左右子結點下標分別爲1和2。排序
1 class Heap { 2 3 4 5 protected $listSize; 6 7 protected $tree; 8 9 10 11 public function __construct($list) { 12 13 $this->listSize = count($list); 14 15 $i = 1; 16 17 foreach ($list as $li) { 18 19 $this->tree[$i++] = $li; 20 21 } 22 23 unset($list); 24 25 $this->initHeap(); 26 27 } 28 29 30 31 public function getSortedResult() { 32 33 $this->initHeap(); 34 35 $this->sortHeap(); 36 37 return $this->tree; 38 39 } 40 41 42 43 public function getHeapResult() { 44 45 return $this->tree; 46 47 } 48 49 50 51 public function getTopNode() { 52 53 return $this->tree[1]; 54 55 } 56 57 58 59 public function setTopNode($value) { 60 61 $this->tree[1] = $value; 62 63 $this->adjustHeap(1, $this->listSize); 64 65 } 66 67 68 69 public function sortHeap() { 70 71 for ($end = $this->listSize; $end > 1; $end--) { 72 73 $this->swap($this->tree[1], $this->tree[$end]); 74 75 $this->adjustHeap(1, $end - 1); 76 77 } 78 79 } 80 81 82 83 private function initHeap() { 84 85 for ($start=floor($len / 2); $start >= 1; $start--) { 86 87 $this->adjustHeap($start, $this->listSize); 88 89 } 90 91 } 92 93 94 95 private function adjustHeap($start, $len) { 96 97 $tmp = $start; // 臨時變量,用於保存最大值或者最小值的下標索引 98 99 $lChildInx = $start * 2; 100 101 $rChildInx = $lChildInx + 1; 102 103 if ($start <= floor($len / 2)) { 104 105 if($lChildInx <= $len && $this->tree[$lChildInx] < $this->tree[$tmp]) { 106 107 $tmp = $lChildInx; 108 109 } 110 111 if($rChildInx <= $len && $this->tree[$rChildInx] < $this->tree[$tmp]) { 112 113 $tmp = $rChildInx; 114 115 } 116 117 if ($tmp != $start) { 118 119 $this->swap($this->tree[$tmp], $this->tree[$start]); 120 121 $this->adjustHeap($tmp, $len); 122 123 } 124 125 } 126 127 } 128 129 130 131 private function swap(&$a, &$b) { 132 133 $temp = $a; 134 135 $a = $b; 136 137 $b = $temp; 138 139 } 140 141 142 143 }
1 include 'Heap.class.php'; 2 3 4 5 $list = range(1,10000); 6 7 shuffle($list); 8 9 $k = 15; 10 11 12 13 $initHeapNodes = array_slice($list, 0, $k); 14 15 $heap = new Heap($initHeapNodes); 16 17 18 19 $n = count($list); 20 21 22 23 for ($i=$k; $i<$n; $i++) { 24 25 if ($list[$i] > $heap->getTopNode()) { 26 27 $heap->setTopNode($list[$i]); 28 29 } 30 31 } 32 33 34 35 print_r($heap->getSortedResult());