原地堆排序

Posted 番茄技术小栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原地堆排序相关的知识,希望对你有一定的参考价值。

做了太久的小程序,6月份之后开始去年的算法的学习,今天比较有感悟的是吴军老师《硅谷来信》的一句话:走完最后的1%,这很重要。主要介绍一下原地堆排序算法以及实现(php)

解释

上一次的博客 算法与数据结构堆和堆排序之堆排序 两种堆排序都需要开辟O(n)的辅助空间(构造函数中使用new分配的辅助空间),程序在开辟辅助空间和释放空间的时候也会消耗一定的时间,若能多数组进行原地堆排序,则省去了开辟和释放空间的时间,时间性能会好一些。

思路

给定一个大小为n的数组,将这个数组heapify,变为最大堆,此时数组的第一个元素就是最大值,将该值与数组最后一个元素交换位置后,对前n-1个元素进行heapify,变成最大堆,将第一个元素与数组倒数第二个元素交换位置...以此类推,最后得到的数组就是从小到大排序的。

  • 注意*

上篇博客中堆排序堆的实现是从1开始,所以当前元素(下标 i)的双亲下标为 i/2,左孩子下标为 2i,右孩子下标为 2i+1;而原地堆排序中直接对数组进行操作,数组的下标是从0开始,所以当前元素(下标i)的双亲为 (i-1)/2,左孩子下标为 2i+1,右孩子下标为 2i+2。

实现

 
   
   
 
  1. <?php

  2. require('../SortingAdvance/QuickSort.php');

  3. /**

  4. * 原地堆排序

  5. */

  6. function shiftDown(&$arr, $n, $i){

  7.    //heapify最后一个非叶子节点, 最后一个节点为:$n-1

  8.    while( 2*$i + 1 < $n ){

  9.        //左节点

  10.        $j = 2*$i + 1;

  11.        //判断右节点是否存在,并且右节点大于左节点

  12.        if( $j+1 < $n && $arr[$j+1] > $arr[$j] ) $j ++;

  13.        if( $arr[$i] >= $arr[$j] ) break;

  14.        // swap( $arr[$i] , $arr[$j] );

  15.        swap( $arr, $i , $j );

  16.        $i = $j;

  17.        // print_r($arr);

  18.    }

  19. }

  20. function selfHeadSort(&$arr, $n){

  21.    //叶子节点已经heapify了,所以从(n-1)/2的非叶子节点开始

  22.    for ($i=(int)(($n-1)/2); $i >=0 ; $i--) {

  23.        shiftDown($arr, $n, $i);

  24.    }

  25.    //$arr已经是一个堆了,下面进行原地堆排序

  26.    //从最后一个元素开始,先和第一个元素交换,然后再对第一个元素heapify

  27.    for ($i=$n-1; $i > 0 ; $i--) {

  28.        swap( $arr, 0 , $i);

  29.        shiftDown($arr, $i, 0);

  30.    }

  31. }

  32. $n = 10000;

  33. $arr = generateRandomArray($n, 0, $n);

  34. $copy_arr1 = $arr;

  35. $copy_arr2 = $arr;

  36. $copy_arr3 = $arr;

  37. $copy_arr4 = $arr;

  38. testSort("selfHeadSort", "selfHeadSort", $arr, $n);

  39. testSort("mergeSort", "mergeSort", $copy_arr1, $n);

  40. testSort("quickSort", "quickSort", $copy_arr2, $n);

  41. testSort("quickSort2", "quickSort2", $copy_arr3, $n);

  42. testSort("quickSort3", "quickSort3", $copy_arr4, $n);

  43. ?>

时间损耗

 
   
   
 
  1. selfHeadSort运行的时间为:0.062602043151855s

  2. mergeSort运行的时间为:0.670814037323s

  3. quickSort运行的时间为:0.033109188079834s

  4. quickSort2运行的时间为:0.021806955337524s

  5. quickSort3运行的时间为:0.054163932800293s


以上是关于原地堆排序的主要内容,如果未能解决你的问题,请参考以下文章

挖掘算法中的数据结构:堆排序之 二叉堆(Heapify原地堆排序优化)

堆排序

九种经典排序算法详解(冒泡排序,插入排序,选择排序,快速排序,归并排序,堆排序,计数排序,桶排序,基数排序)

Java排序算法 - 堆排序的代码

逐句解释堆排序

逐句解释堆排序