a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。
堆排序是一种不稳定排序,相同的值不能保证原样的位置。
github地址: https://github.com/luolaifa000/phpStudyCode/blob/master/HeapSort.php
<?php
function pre($arr)
{
$data = func_get_args();
foreach($data as $key=>$val)
{
echo '<pre>';
print_r($val);
echo '</pre>';
}
}
function prend()
{
$data = func_get_args();
foreach($data as $key=>$val)
{
echo '<pre>';
print_r($val);
echo '</pre>';
}
exit();
}
/**
*
* 构建大堆序
*
* @author laifaluo
* github https://github.com/luolaifa000/phpStudyCode/blob/master/HeapSort.php
*
*/
class HeapSort {
public $data;
public function __construct(Array $array)
{
$this->data = $array;
}
/**
* 将数组初始化构建堆
* 从最后一个非叶子节点开始,递归到第0个, index = n/2 -1
*
*/
public function buildHeap()
{
$noLeafNodeIndex = floor(count($this->data)/2) - 1;
for ($i = $noLeafNodeIndex; $i>=0; $i--) {
$this->adjustHeap($i,count($this->data));
}
pre("构建后",$this->data);
//prend($noLeafNodeIndex);
}
/**
* 交换头尾,在构建堆
*
*/
public function sortHeap()
{
$k = 1;
for ($i = count($this->data) - 1; $i > 0 ; $i--) {
//每次构建好堆后,交换头尾
$temp = $this->data[$i];
$this->data[$i] = $this->data[0];
$this->data[0] = $temp;
pre("第".$k."趟,交换头尾后",$this->data);
if ($k == 3) {
$this->adjustHeap1(0,$i);
}
//交换头尾后,按照堆规则,重新构建堆
$this->adjustHeap(0,$i);
pre("第".$k."趟,构建完堆后",$this->data);
$k++;
}
}
/**
* 按照堆规则,重新构建堆
*
* @param int $parentIndex
* @param int $length
*/
public function adjustHeap(int $parentIndex,int $length)
{
$childIndex = 2*$parentIndex + 1;
while ($childIndex < $length) {
if ($childIndex+1 < $length && isset($this->data[$childIndex+1]) && $this->data[$childIndex+1] >$this->data[$childIndex]) {
$childIndex++;
}
if ($this->data[$parentIndex] >= $this->data[$childIndex]) {
break;
}
$temp = $this->data[$parentIndex];
$this->data[$parentIndex] = $this->data[$childIndex];
$this->data[$childIndex] = $temp;
$parentIndex = $childIndex;
$childIndex = 2*$parentIndex + 1;
}
}
/**
*
* 用来做特殊调试的
* @param int $parentIndex
* @param int $length
*/
public function adjustHeap1(int $parentIndex,int $length)
{
$childIndex = 2*$parentIndex + 1;
while ($childIndex < $length) {
if ($childIndex+1 < $length && isset($this->data[$childIndex+1]) && $this->data[$childIndex+1] >$this->data[$childIndex]) {
$childIndex++;
}
if ($this->data[$parentIndex] >= $this->data[$childIndex]) {
break;
}
$temp = $this->data[$parentIndex];
$this->data[$parentIndex] = $this->data[$childIndex];
$this->data[$childIndex] = $temp;
$parentIndex = $childIndex;
$childIndex = 2*$parentIndex + 1;
}
}
}
$heapSort = new HeapSort([20,50,10,30,70,20,80]);
pre("初始数组",$heapSort->data);
$heapSort->buildHeap();
$heapSort->sortHeap();
pre("已排序数组",$heapSort->data);
?>