堆排序

数据结构 数组
最差时间复杂度 O(n*log n)
最优时间复杂度 O(n*log n)
平均时间复杂度 O(n*log n)
最差空间复杂度 О(n) total, O(1) auxiliary

1、堆的基础知识

堆节点的访问

通常堆是通过一维数组来实现的。在数组起始位置为0的情形中:

  • 父节点i的左子节点在位置(2*i+1);
  • 父节点i的右子节点在位置(2*i+2);
  • 子节点i的父节点在位置floor((i-1)/2);

堆的操作

在堆的数据结构中,堆中的最大值总是位于根节点。堆中定义以下几种操作:

  • 最大堆调整(Max_Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
  • 创建最大堆(Build_Max_Heap):将堆所有数据重新排序
  • 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算

2、算法思想

  1. 调用创建堆函数将输入数组A[1...n]造成一个最大堆,使得最大的值存放在数组第一个位置A[1]
  2. 然后用数组最后一个位置元素与第一个位置进行交换,并将堆的大小减少1
  3. 调用最大堆调整函数从第一个位置调整最大堆

3、伪代码

//from 算法导论1.下标计算[为与程序对应,下标从0开始]
Parent(i)://为了伪代码描述方便
return i/2Left(i):
return 2*i+1Right(i):
return 2*i+22.使下标i元素为根的的子树成为最大堆MAX_HEAPIFY(A,i):
l<——Left(i)r<——Right(i)if l<length(A)and A[l]>A[i]
thenlargest<——lelse largest<——iif r<length(A)and A[r]>A[largest]
thenlargest<——rif largest!=ithen exchange A[i]<——>A[largest]//到这里完成了一层下降
MAX_HEAPIFY(A,largest)//这里是递归的让当前元素下降到最低位置3.最大堆的建立,将数组A编译成一个最大堆BUILD_MAX_HEAP(A):
heapsize[A]<——length[A]
for i<——length[A]/2+1  to0MAX_HEAPIFY(A,i)//堆排序的开始首先要构造大顶堆,这里就是对内层节点进行逐级下沉(小元素)4.堆排序HEAP_SORT(A):
BUILD_MAX_HEAP(A)for i<——length[A]-1to1//这里能够保证堆大小和数组大小的关系,堆在每一次置换后都减一do exchangeA[1]<——>  A[i]
length[A]<——length[A]-1MAX_HEAPIFY(A,0)//对交换后的元素下沉

4、实现

#include <stdio.h>
#include <stdlib.h>void swap(int* a, int* b) {int temp = *b;*b = *a;*a = temp;
}void max_heapify(int arr[], int start, int end) {//建立父節點指標和子節點指標int dad = start;int son = dad * 2 + 1;while (son <= end) { //若子節點指標在範圍內才做比較if (son + 1 <= end && arr[son] < arr[son + 1]) //先比較兩個子節點大小,選擇最大的son++;if (arr[dad] > arr[son]) //如果父節點大於子節點代表調整完畢,直接跳出函數return;else { //否則交換父子內容再繼續子節點和孫節點比較swap(&arr[dad], &arr[son]);dad = son;son = dad * 2 + 1;}}
}void heap_sort(int arr[], int len) {int i;//初始化,i從最後一個父節點開始調整for (i = len / 2 - 1; i >= 0; i--)max_heapify(arr, i, len - 1);//先將第一個元素和已排好元素前一位做交換,再從新調整,直到排序完畢for (i = len - 1; i > 0; i--) {swap(&arr[0], &arr[i]);max_heapify(arr, 0, i - 1);}
}int main() {int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };int len = (int) sizeof(arr) / sizeof(*arr);heap_sort(arr, len);int i;for (i = 0; i < len; i++)printf("%d ", arr[i]);printf("\n");system("pause");return 0;
}

5、复杂度分析

”1、它的运行时间主要是消耗在初始构建堆和在重建堆时的反复筛选上。

(1)在构建堆的过程中,因为我们是完全二叉树从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和若有必要的互换,对于每个非终端结点来说,其实最多进行两次比较和互换操作,因此整个构建堆的时间复杂度为O(n)

(2)在正式排序时,第i次取堆顶记录重建堆需要用O(logi)的时间(完全二叉树的某个结点到根结点的距离为log2i+1),并且需要取n-1次堆顶记录,因此,重建堆的时间复杂度为O(n*log n)

所以总体来说,堆排序的时间复杂度为O(n*logn)。由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为O(n*logn)。这在性能上显然要远远好过于冒泡、简单选择、直接插入的O(n2)的时间复杂度了。

2、空间复杂度上,需要一个单元的辅助空间用于交换,所以辅助空间为O(1)。

不过由于记录的比较与交换是跳跃式进行,因此堆排序是一种不稳定的排序方法。”——引用自冰河的博客http://blog.csdn.net/u012152619/article/details/47452813#t2

转载于:https://www.cnblogs.com/crystalmoore/p/5931587.html

经典排序算法学习笔记七——堆排序相关推荐

  1. 经典排序算法学习笔记二——快速排序

    快速排序 数据结构 不定 最差时间复杂度 O(n^2) 最优时间复杂度 O (n*log n) 平均时间复杂度 O (n*log n) 最差空间复杂度 根据实现的方式不同而不同 https://zh. ...

  2. 常见经典排序算法学习总结(插入、shell、冒泡、选择、归并、快排等)

    博主在学习过程中深感基础的重要,经典排序算法是数据结构与算法学习过程中重要的一环,这里对笔试面试最常涉及到的7种排序算法(包括插入排序.希尔排序.选择排序.冒泡排序.快速排序.堆排序.归并排序)进行了 ...

  3. 十大经典排序算法详解(三)-堆排序,计数排序,桶排序,基数排序

    养成习惯,先赞后看!!! 你的点赞与关注真的对我非常有帮助.如果可以的话,动动手指,一键三连吧!!! 十大经典排序算法-堆排序,计数排序,桶排序,基数排序 前言 这是十大经典排序算法详解的最后一篇了. ...

  4. 【算法学习笔记】堆排序和归并排序、其他几种排序的代码实现、比较和应用(习题)

    文章目录 基本堆排序 1.有20个数组,每个数组有500个元素,且是有序的,如何在20*500个数中找出排名前500的数 设有两个递增的序列a,b 长度都为n,求前k个最小的a[i]+b[j] 若要在 ...

  5. 经典排序算法(7)——堆排序算法详解

    堆排序(Heap sort)是指利用堆(最大堆.最小堆)这种数据结构所设计的一种排序算法.堆是一个完全二叉树的结构,并同时满足如下性质:即子结点的键值或索引总是小于(或者大于)它的父节点. 一.算法基 ...

  6. 【基础】排序算法学习笔记

    NOIP范畴常见的排序一般是这几种 1.冒泡排序,选择排序,插入排序 2.快速排序,归并排序,堆排序 3.计数排序,基数排序,桶排序 前两类是基于比较的,第三类是基于统计的. 第一类都是O(N^2)的 ...

  7. 输出dag的所有拓扑排序序列_算法学习笔记(53): 拓扑排序

    拓扑排序是对DAG(有向无环图)上的节点进行排序,使得对于每一条有向边 , 都在 之前出现.简单地说,是在不破坏节点 先后顺序的前提下,把DAG拉成一条链.如果以游戏中的科技树(虽然名字带树,其实常常 ...

  8. 算法学习笔记17:堆、堆排序

    目录 堆和堆排序:为什么说堆排序没有快速排序快 如何理解"堆" 如何实现一个堆 1. 往堆中插入一个元素 2. 删除堆顶元素 如何基于堆实现排序 1. 建堆 2. 排序 解答开篇 ...

  9. python遍历数组冒泡排序_经典排序算法(冒泡排序,选择排序,插入排序,快速排序,堆排序)python实现...

    最近在复习经典排序算法,自己用python也实现了一下,这里不会涉及到原理(因为网上方法已经很详细啦),就把函数贴上来,可以让大家自己试着运行下,再结合别处的原理也可以更好地理解它们的实现. 如果有错 ...

最新文章

  1. mysql cronjob 备份_mysql 数据备份 crontab
  2. Java 如何线程间通信,面试被问哭。。。
  3. Py之argparse:Python库之argparse(命令行解析)简介、安装、使用方法之详细攻略
  4. 静态变数和非静态变数_统计资料:了解变数
  5. 8 种架构设计模式优缺点大曝光 | 原力计划
  6. 鸿蒙空间是什么星辰变,飞升之后做什么《星辰变》神魔妖界收伏奇珍异兽
  7. uinput 用法 android 上层使用uinput 的用法来模拟 input 事件
  8. 用Netfilter模块实现基于令牌桶的每IP地址流量控制
  9. MySQL批量插入(使用mybatis实现mysql数据库的批量插入操作)
  10. 图像分割(语义分割)的局限以及解决方法
  11. antd tooltip 修改样式
  12. 医院排队叫号系统(JAVA版)
  13. 一寸照片压缩到20k_师大er:关于证件照你需要知道这些干货!(/^^)/ 顺便免费冲印高清照片~...
  14. 小学计算机课第二课堂活动总结,小学课外活动总结范文_2020小学第二课堂工作总结精选...
  15. VS编译运行时出现exe文件无法打开的原因
  16. cbac式_abca式的成语
  17. 如何在mac上输入无穷大infinity符号:∞
  18. 图论学习--7 图的着色(思维导图)边着色 点着色 色多项式 临界图与完美图
  19. 对近期自我状态的反思及总结
  20. opencv读入灰度图片却显示三通道

热门文章

  1. 你们听过最感人的故事是什么?
  2. 22年前,100万买入谷歌原始股,奥尼尔的股份如今市值多少?
  3. 腾讯正式入局中视频领域
  4. 大家觉得现在最赚钱的电商形式是什么?
  5. 搭建私域流量池实施落地——四大运营步骤
  6. 函数式编程(Functional Programming)
  7. 配电脑时什么配置可以缩水?
  8. The idea of ​​router network configuration
  9. MTK eCos系统的有线驱动收包流程
  10. 限制进程使用的内存大小和CPU时间