今天比较有感悟的是吴军老师《硅谷来信》的一句话:走完最后的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