堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或大于)它的父结点。
思路:
1、将待排序序列构造成一个大顶堆
2、此时,整个序列的最大值就是堆顶的根节点
3、将其与末尾元素进行交换,此时末尾就为最大值
4、然后将剩余n-1个元素重新构造成一个堆,这样就会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
注:每个结点的值都大于或等于其左右子结点的值,称为大顶堆;
每个结点的值都小于或等于其左右子结点的值,称为小顶堆。
小顶堆(降序)
<?php
//因为是数组,下标从0开始,所以,下标为n根结点的左子结点为2n+1,右子结点为2n+2;
//初始化值,建立初始堆
$arr=array(49,38,65,97,76,13,27,50);
$arrSize=count($arr);
//将第一次排序抽出来,因为最后一次排序不需要再交换值了。
buildHeap($arr,$arrSize);
for($i=$arrSize-1;$i>0;$i--){
swap($arr,$i,0);
$arrSize--;
buildHeap($arr,$arrSize);
}
print_r($arr);
//用数组建立最小堆
function buildHeap(&$arr,$arrSize){
//计算出最开始的下标$index,比较每一个子树的父结点和子结点,将最小值存入父结点中
//从$index处对一个树进行循环比较,形成最小堆
for($index=intval($arrSize/2)-1; $index>=0; $index--){
//如果有左节点,将其下标存进最小值$min
if($index*2+1<$arrSize){
$min=$index*2+1;
//如果有右子结点,比较左右结点的大小,如果右子结点更小,将其结点的下标记录进最小值$min
if($index*2+2<$arrSize){
if($arr[$index*2+2]<$arr[$min]){
$min=$index*2+2;
}
}
//将子结点中较小的和父结点比较,若子结点较小,与父结点交换位置,同时更新较小
if($arr[$min]<$arr[$index]){
swap($arr,$min,$index);
}
}
}
}
//此函数用来交换下数组$arr中下标为$one和$another的数据
function swap(&$arr,$one,$another){
$tmp=$arr[$one];
$arr[$one]=$arr[$another];
$arr[$another]=$tmp;
}
?>
大顶堆(升序)
<?php
/**
* 将数组初始化构建堆
* 从最后一个非叶子节点开始,递归到第0个, index = n/2 -1
*
*/
function buildHeap(&$arr)
{
$noLeafNodeIndex = floor(count($arr)/2) - 1;
for ($i = $noLeafNodeIndex; $i>=0; $i--) {
adjustHeap($arr,$i,count($arr));
}
}
/**
* 交换头尾,在构建堆
*
*/
function sortHeap(&$arr)
{
$k = 1;
for ($i = count($arr) - 1; $i > 0 ; $i--) {
//每次构建好堆后,交换头尾
$temp = $arr[$i];
$arr[$i] = $arr[0];
$arr[0] = $temp;
if ($k == 3) {
adjustHeap1($arr,0,$i);
}
//交换头尾后,按照堆规则,重新构建堆
adjustHeap($arr,0,$i);
$k++;
}
}
/**
* 按照堆规则,重新构建堆
*
* @param int $parentIndex
* @param int $length
*/
function adjustHeap(&$arr,$parentIndex,$length)
{
$childIndex = 2*$parentIndex + 1;
while ($childIndex < $length) {
if ($childIndex+1 < $length && isset($arr[$childIndex+1]) && $arr[$childIndex+1] >$arr[$childIndex]) {
$childIndex++;
}
if ($arr[$parentIndex] >= $arr[$childIndex]) {
break;
}
$temp = $arr[$parentIndex];
$arr[$parentIndex] = $arr[$childIndex];
$arr[$childIndex] = $temp;
$parentIndex = $childIndex;
$childIndex = 2*$parentIndex + 1;
}
}
/**
*
* 用来做特殊调试的
* @param int $parentIndex
* @param int $length
*/
function adjustHeap1(&$arr,$parentIndex,$length)
{
$childIndex = 2*$parentIndex + 1;
while ($childIndex < $length) {
if ($childIndex+1 < $length && isset($arr[$childIndex+1]) && $arr[$childIndex+1] >$arr[$childIndex]) {
$childIndex++;
}
if ($arr[$parentIndex] >= $arr[$childIndex]) {
break;
}
$temp = $arr[$parentIndex];
$arr[$parentIndex] = $arr[$childIndex];
$arr[$childIndex] = $temp;
$parentIndex = $childIndex;
$childIndex = 2*$parentIndex + 1;
}
}
$arr = [20,50,10,30,70,20,80];
buildHeap($arr);
sortHeap($arr);
print_r($arr);
?>