今天比較有感悟的是吳軍老師《硅谷來信》的一句話:走完最後的1%,這很重要。主要介紹一下原地堆排序算法以及實現(PHP)php
上一次的博客 算法與數據結構堆和堆排序之堆排序 兩種堆排序都須要開闢O(n)的輔助空間(構造函數中使用new分配的輔助空間),程序在開闢輔助空間和釋放空間的時候也會消耗必定的時間,若能多數組進行原地堆排序,則省去了開闢和釋放空間的時間,時間性能會好一些。算法
給定一個大小爲n的數組,將這個數組heapify,變爲最大堆,此時數組的第一個元素就是最大值,將該值與數組最後一個元素交換位置後,對前n-1個元素進行heapify,變成最大堆,將第一個元素與數組倒數第二個元素交換位置...以此類推,最後獲得的數組就是從小到大排序的。api
上篇博客中堆排序堆的實現是從1開始,因此當前元素(下標 i)的雙親下標爲 i/2,左孩子下標爲 2i,右孩子下標爲 2i+1;而原地堆排序中直接對數組進行操做,數組的下標是從0開始,因此當前元素(下標i)的雙親爲 (i-1)/2,左孩子下標爲 2i+1,右孩子下標爲 2i+2。數組
<?php
require('../SortingAdvance/QuickSort.php');
/** * 原地堆排序 */
function shiftDown(&$arr, $n, $i){
//heapify最後一個非葉子節點, 最後一個節點爲:$n-1
while( 2*$i + 1 < $n ){
//左節點
$j = 2*$i + 1;
//判斷右節點是否存在,而且右節點大於左節點
if( $j+1 < $n && $arr[$j+1] > $arr[$j] ) $j ++;
if( $arr[$i] >= $arr[$j] ) break;
// swap( $arr[$i] , $arr[$j] );
swap( $arr, $i , $j );
$i = $j;
// print_r($arr);
}
}
function selfHeadSort(&$arr, $n){
//葉子節點已經heapify了,因此從(n-1)/2的非葉子節點開始
for ($i=(int)(($n-1)/2); $i >=0 ; $i--) {
shiftDown($arr, $n, $i);
}
//$arr已是一個堆了,下面進行原地堆排序
//從最後一個元素開始,先和第一個元素交換,而後再對第一個元素heapify
for ($i=$n-1; $i > 0 ; $i--) {
swap( $arr, 0 , $i);
shiftDown($arr, $i, 0);
}
}
$n = 10000;
$arr = generateRandomArray($n, 0, $n);
$copy_arr1 = $arr;
$copy_arr2 = $arr;
$copy_arr3 = $arr;
$copy_arr4 = $arr;
testSort("selfHeadSort", "selfHeadSort", $arr, $n);
testSort("mergeSort", "mergeSort", $copy_arr1, $n);
testSort("quickSort", "quickSort", $copy_arr2, $n);
testSort("quickSort2", "quickSort2", $copy_arr3, $n);
testSort("quickSort3", "quickSort3", $copy_arr4, $n);
?>
複製代碼
selfHeadSort運行的時間爲:0.062602043151855s
mergeSort運行的時間爲:0.670814037323s
quickSort運行的時間爲:0.033109188079834s
quickSort2運行的時間爲:0.021806955337524s
quickSort3運行的時間爲:0.054163932800293s
複製代碼
-------------------------華麗的分割線--------------------bash
看完的朋友能夠點個喜歡/關注,您的支持是對我最大的鼓勵。微信
想了解更多,歡迎關注個人微信公衆號:番茄技術小棧dom