排序算法——堆排序

简介: 排序算法——堆排序

一、算法介绍


1.算法思想

堆排序是指利用堆这种数据结果所设计的一种排序算法,堆排序也是选择排序的一种,只不过是通过堆来进行选择,其核心思想主要包括建堆和堆排序两步操作:


建堆:


‘首先要将所给定的序列在逻辑上看作是一棵完全二叉树,然后根据完全二叉树的特点,从完全二叉树倒数第一个非叶子节点开始,利用向下调整算法依次往前调整,这样就可以将完全二叉树调整为一个堆。


堆排序:


堆排序主要是利用堆删除的思想来进行排序:将堆顶与末尾位置进行交换,此时必然会破坏堆的结构,所以在交换后,需要重新对二叉树进行调整使之重新成为一个堆,但是交换后来的元素不会参与后续的调整,这里可以通过设置一个末尾标志位实现,没完成一次交换,末尾标志位向前移动一位,直到调整完整个序列,完成堆排序。


2.算法流程


image.png


注:根据堆的特性和堆排序的思想,排升序需要建大堆,排降序需要建小堆。


对于堆的相关知识及详细实现过程可以参考往期博客。


二、算法实现


1.代码实现


#include<stdio.h>
#include<stdlib.h>
//堆排序---->利用堆删除的思想来进行排序      升序:大堆   降序:小堆
void Test_HeapSort();
void HeapSort(int* array, int n);//堆排序
void AdjustDown(int* array, int parent, int size);//堆排序子函数->向下调整法
int Min(int num1, int num2);//降序--小堆
int Max(int num1, int num2);//升序--大堆
void Swap(int* parent, int* child);//交换双亲结点与孩子结点
void Printf_array(int* array, int length);//数组打印函数
int main() {
  Test_HeapSort();
  return 0;
}
void Test_HeapSort() {
  int array[] = { 49, 27, 37, 65, 28, 34, 25, 15, 18, 19 };
  int length = sizeof(array) / sizeof(array[0]);
  printf("排序前:");
  Printf_array(array, length);
  HeapSort(array, length);// 对数组进行堆排序
  printf("\n排序后:");
  Printf_array(array, length);
}
void HeapSort(int* array, int n) {//堆排序
  //1.建堆
  for (int root = ((n - 1) - 1) / 2; root >= 0; root--) {//n-1为最后一个叶子结点的下标,root为该结点的双亲
  AdjustDown(array, root, n);//向下调整
  }
  //2.利用堆删除的思想来进行排序
  int end = n - 1;//标记调整位置的最大下标
  while (end) {
  int temp = array[0];
  array[0] = array[end];
  array[end] = temp;
  AdjustDown(array, 0, end);
  end--;
  }
}
void AdjustDown(int* array, int parent, int size) {//向下调整
  int child = parent * 2 + 1;//标记左孩子
  while (child < size) {
  if (child + 1 < size && Max(array[child + 1], array[child])) {//找左右孩子较小的孩子
    child += 1;
  }
  if (Max(array[child], array[parent])) {//检测是否满足堆的特性
    Swap(&array[parent], &array[child]);//不满足,交换并继续向下调整
    parent = child;
    child = parent * 2 + 1;
  }
  else {//满足,直接返回
    return;
  }
  }
}
void Swap(int* parent, int* child) {//整数交换
  int temp = *parent;
  *parent = *child;
  *child = temp;
}
void Printf_array(int* array, int length) {//数组打印函数
  for (int i = 0; i < length; i++) {
  printf("%d ", array[i]);
  }
}
int Min(int num1, int num2) {//降序--小堆
  return num1 < num2;
}
int Max(int num1, int num2) {//升序--大堆
  return num1 > num2;
}


2.测试用例及结果

测试用例:


array[]={49,27,37,65,28,34,25,15,18,19}


测试结果:


1.png


三、性能分析


1.时间复杂度


根据算法排序思想,每次交换堆顶与末尾元素完成一个元素的排序之后都需要利用向下调整算法将二叉树重新调整为堆,而单次调整的时间复杂度为,所以对于n个元素,堆排序的时间复杂度为。


2.空间复杂度


由于算法中除了定义一些临时变量外,没有借助额外的辅助空间,所以堆排序的空间复杂度为O(1)。


3.稳定性


因为堆排序在元素交换时是隔着元素进行交换的,所以过程中会改变相同元素的相对位置,所以堆排序是不稳定的。


相关文章
|
16天前
|
算法 Python
数据结构算法--4堆排序
堆排序过程概述:建立大根堆,将堆顶最大元素移出并替换为末尾元素,调整保持堆性质,重复此过程直至堆为空,实现排序。时间复杂度为O(nlogn)。Python中可用heapq模块进行堆操作。
|
2月前
|
机器学习/深度学习 人工智能 算法
数据结构与算法:堆排序和TOP-K问题
朋友们大家好,本节内容来到堆的应用:堆排序和topk问题
数据结构与算法:堆排序和TOP-K问题
|
2月前
|
存储 人工智能 算法
深入浅出堆排序: 高效算法背后的原理与性能
深入浅出堆排序: 高效算法背后的原理与性能
59 1
|
10天前
|
算法 搜索推荐 Java
Java数据结构与算法:排序算法之堆排序
Java数据结构与算法:排序算法之堆排序
|
2月前
|
移动开发 算法 前端开发
前端算法之堆排序
前端算法之堆排序
23 1
|
16天前
|
搜索推荐 算法 Java
Java中的快速排序、归并排序和堆排序是常见的排序算法。
【6月更文挑战第21天】Java中的快速排序、归并排序和堆排序是常见的排序算法。快速排序采用分治,以基准元素划分数组并递归排序;归并排序同样分治,先分割再合并有序子数组;堆排序通过构建堆来排序,保持堆性质并交换堆顶元素。每种算法各有优劣:快排平均高效,最坏O(n²);归并稳定O(n log n)但需额外空间;堆排序O(n log n)且原地排序,但不稳定。
21 3
|
13天前
|
搜索推荐 算法
【C/排序算法】:堆排序和选择排序
【C/排序算法】:堆排序和选择排序
9 0
|
1月前
|
存储 算法 C语言
数据结构和算法——堆排序(选择排序、思路图解、代码、时间复杂度、堆排序及代码)
数据结构和算法——堆排序(选择排序、思路图解、代码、时间复杂度、堆排序及代码)
16 0
|
2月前
|
算法 搜索推荐
数据结构与算法⑫(第四章_中_续一)堆排序(详解)
数据结构与算法⑫(第四章_中_续一)堆排序(详解)
29 0
|
2月前
|
人工智能 搜索推荐 算法
sort-04-heap sort 堆排序算法详解
这是一个关于排序算法的系列文章摘要,包括了10篇关于不同排序算法的链接,如冒泡排序、快速排序、选择排序、堆排序等。堆排序是一种基于比较的排序算法,利用了近似完全二叉树的结构并满足最大堆或最小堆的性质。最大堆中,每个节点的值都大于或等于其子节点。文章详细解释了最大堆的概念、节点访问方式以及堆的操作,包括堆调整和堆排序的过程,并通过图解展示了堆排序的具体步骤。此外,还提供了一个Java实现的堆排序代码示例。整个排序系列来源于一个开源项目,读者可以通过链接查看完整内容。
sort-04-heap sort 堆排序算法详解