详解堆排序

简介: 详解堆排序

堆再内存中是以数组的形式存储的,所以是层序。在逻辑上是一颗二叉树,而且只能是满二叉树或完全二叉树。如果堆的顺序被打乱,就需要向下调整函数重新建堆。

本篇使用建小堆和逆序的逻辑

向下调整函数

示意图: 代码如下:

//向下调
void AdjustDwon(HPDataType* a, int n, int parent)//n是数据个数   
{
  assert(a);
  int child = parent * 2 + 1; //左孩子  
  //左孩子等于父亲乘2加1
  while (child < n)
  {
    //如果右孩子没越界, 并且左右孩子中右孩子较小, 就选右孩子
    if (child + 1 < n && a[child] > a[child + 1])
    {
      child++;
    }
 
    //只要孩子小于父亲,就下调, 直到调到合适的位置
    if (a[child] < a[parent])
    {
      //交换父亲和孩子的数据
      HPDataType tmp = 0;
      tmp = a[child];
      a[child] = a[parent];
      a[parent] = tmp;
 
      //更改下标,孩子的数据挪到了父亲的位置,下标自然也要挪
      parent = child;
      child = parent * 2 + 1;
    }
    else
    {
      break;
    }
  }
 
}

建堆

如果数组是完全无序,则不断的需要使用向下调整函数建堆。

示意图: 代码如下:

for (int i = (n - 1 - 1) / 2; i >= 0; i--)  /*向下调整建小堆   n - 1是最后一个孩子的下标,((n - 1)- 1)/2 是最后一个父亲的下标*/
{
  if (a[i] >= a[i * 2 + 1] || a[i] >= a[i * 2 + 1 + 1])  //如果父亲比孩子大,就需要父亲下调重新建队
  {
    AdjustDwon(a, n, i); //下调
  }
}

这样我们就建好堆了。

排序

堆的第一个数一定是最小的(小堆),把第一个数和最后一个数交换,这样就排好一个数了,再因为最后一个数再第一的位置,所以让总数减一,调用向下调整函数重新建堆,再把第一个数和最后一个数交换,如此往复,直到数组有序。代码如下:

for (int i = n; i > 0; i--)  
{
  //把第一个数据和最后一个数据交换
  int tmp = a[i - 1];      //i 是个数  i-1 是下标
  a[i - 1] = a[0];
  a[0] = tmp;
 
  AdjustDwon(a, i - 1, 0);  // i-1 和 i-1 的右边已经是有序数组,不需要参与堆的重新排序
}

时间复杂度:

专门写了以篇文章讲复杂度,去看看吧

相关文章
|
2月前
|
存储 搜索推荐 算法
堆排序讲解
堆排序讲解
24 4
|
6月前
|
分布式计算 搜索推荐 Java
堆排序就是这么容易
堆排序就是这么容易
53 0
|
7月前
|
算法 搜索推荐 Java
选择排序 - 堆排序
选择排序 - 堆排序
选择排序 - 堆排序
|
7月前
|
搜索推荐 算法
【排序算法】堆排序详解与实现
【排序算法】堆排序详解与实现
|
7月前
|
搜索推荐 算法 C++
C++堆排序的实现
C++堆排序的实现
|
7月前
|
存储
堆排序、快速排序和归并排序
堆排序、快速排序和归并排序
59 0
|
7月前
选择排序与堆排序
选择排序与堆排序
51 0
|
7月前
|
算法 搜索推荐 索引
堆排序详细解读
堆排序详细解读
66 0
|
7月前
|
搜索推荐 算法 Java
java排序算法:快速排序、归并排序、堆排序等
排序算法:快速排序、归并排序、堆排序等
102 0
|
算法 索引 搜索推荐