標籤:style blog java color 使用 strong
幾句廢話先:
本人最近在學習研究資料結構和演算法,之所以為什麼學習它,第一:是我看到到了現在學習的瓶頸,一直停留在使用別人的什麼什麼架構或者演算法之類的東西,沒有對程式更深層次的學習探究。第二:想在IT行業走得更加的長遠,資料結構是必須要邁的一道坎。
另外本人從上一篇部落格開始已經步入javascript,不在或者很少探討.NET平台相關內容。
主題:
arr.heap-size
至於什麼事堆,我在這裡也不再的囉嗦,閱讀本博文,已經預設你認識它,如果您是大牛,請忽視本博文或者找我的錯,我很歡迎 :)
在堆排序之前我們要Crowdsourced Security Testing道一個非常基礎的一個東西就是arr.heap-size。我剛開始看的時候,對這個不怎麼重視,覺得,它不就是等於arr.length嗎?並且在學習之初的建堆上,也沒有多大的用處,但是在後面的排序中,最佳化效能方面它發揮了很大的作用。它的定義說白了就是在一個數組arr中有效元素個數,換句話說:arr[1,arr.length]中可能有資料,但是在arr[1,arr.heap-size]中存放的是有效資料。
最大堆
在有些書上,對於最大堆的定義有些囉嗦(個人覺得),其實說白了就是除了根節點外,任何一個孩子的根節點相對其孩子來說是最大的。至於最小堆就是它的反向。最小堆是用於構造優先隊列的,這裡暫時不說,畢竟現在都23點了,明兒還要早起,扯遠了。。在以後的博文中會陸續講解。最大堆的性質也就是它的定義所說的,維護最大堆的性質的時間複雜度是大Ο(log2 N) ,這裡的N不是方!!
我們先來看看怎麼樣去維護一個堆的性質:
下面用JS吧,畢竟現在日常就是用JS,啥語言都一樣:
var arr = [4,1,3,2,16,9,10,14,8,7], heapLen = arr.length, halfLen = heapLen / 2, laster;function buidHeap(i){var left = 2 * i + 1,right = 2 * i + 2;if(left < heapLen && arr[left] > arr[i]){laster = left;}else{laster = i;}if(right < heapLen && arr[right] > arr[laster]){laster = right;}if(laster !== i){var temp;temp = arr[i];arr[i] = arr[laster];arr[laster] = temp;buidHeap(laster);}}
維護最大堆的一個最主要的思想就是始終堅持它的性質,我們在arr[i]、arr[left]和arr[right]中選出最大的,並且將它的下標儲存在laster中,但是在交換了之後考慮到還要繼續維護它的性質,我們可以進行遞迴的調用。維護一個最大堆的代價也就是兩個:第一:arr[i]、arr[left]和arr[right]的調換是常數時間,任意一個孩子的子樹是≤2/3 * n的
所以它的時間T(n) = T(2/3 *N);
在上面我們只是在維護最大堆的性質,那麼我們怎麼去建堆那?
var arr = [4,1,3,2,16,9,10,14,8,7], heapLen = arr.length, halfLen = heapLen / 2, laster;function buidHeap(i){var left = 2 * i + 1,right = 2 * i + 2;if(left < heapLen && arr[left] > arr[i]){laster = left;}else{laster = i;}if(right < heapLen && arr[right] > arr[laster]){laster = right;}if(laster !== i){var temp;temp = arr[i];arr[i] = arr[laster];arr[laster] = temp;buidHeap(laster);}}function exe(cb){for(var i = heapLen;i >= 0;i--){buidHeap(i);}cb();}
最下面的exe()函數就是一個建堆的過程。
到這我們的堆就已經建好了,我們的堆排序怎麼實現?
實現堆排序:
這裡有兩個辦法,第一個將已經刷選出的元素放在另外一個數組中,因為在最大堆中,根節點最大,所以我們每移除一次根節點都要在進行一次最大堆性質的維護。但是複製到新的一個數組這樣就消耗了兩倍的空間,這樣做雖然可以實現最終的目的,但是還是不怎麼好。第二個辦法就是在本博文開始不是說到heap-size了嗎,在這裡就用上了,它表示的是有效元素,既然是有效,我們每一次刷選後,把最大元素放在最後,同時heap-size - 1;這樣不就節省了空間了嗎?
代碼:
var arr = [4,1,3,2,16,9,10,14,8,7], heapLen = arr.length, halfLen = heapLen / 2, laster;function buidHeap(i){var left = 2 * i + 1,right = 2 * i + 2;if(left < heapLen && arr[left] > arr[i]){laster = left;}else{laster = i;}if(right < heapLen && arr[right] > arr[laster]){laster = right;}if(laster !== i){var temp;temp = arr[i];arr[i] = arr[laster];arr[laster] = temp;buidHeap(laster);}}function exe(cb){for(var i = heapLen;i >= 0;i--){buidHeap(i);}cb();}function buidMaxHeap(cb){exe(function(){console.log(‘------最大堆已建好------‘);for(var i = arr.length - 1;i>=1;i--){var temp;temp = arr[0];arr[0] = arr[i];arr[i] = temp;heapLen -= 1;buidHeap(0);}});cb();};(function heapsort(){buidMaxHeap(function(){console.log(‘------堆排序已派好------‘);for(var i = 0;i<arr.length;i++){console.log(arr[i]);}});})();
最後想說:
本博文只是對堆排序的淺意義上的說明,沒有更深次的探討它的時間複雜度,第一個原因就是一些數學符號弄不出來,第二個就是:我個人語言表現力不足,你可以Google之。
本博文屬於原創,允許轉載,但請標明原始串連來源!!