堆排序

来源:互联网 发布:税控接口软件 编辑:程序博客网 时间:2024/06/07 13:29

堆排序

堆的概念

​ 堆本身为一棵完全二叉树,即拥有的特点是n个结点的堆的高度为logn+1,若将堆按照1….n的按层进行编号则第i个结点如果有左孩子的话则它的左孩子的为第2×i个结点,如果它有右孩子的话右孩子为第2×i+1个结点,可以利用这个性质将数组构建成一个堆并且进行方便的索引。

​ 堆分为大根堆和小根堆。

​ 大根堆指所有结点的关键字不小于其子结点的关键字的完全二叉树。

​ 小根堆指所有结点的关键字不大于其子节点的关键字的完全二叉树。

这里写图片描述

堆排序原理和过程

​ 堆排序就是利用了大根堆和小根堆的其整棵树的根结点一定是整棵树的最大值或者最小值这个性质。

​ 流程:

​ 1、将带排序的序列构建成一个堆结构;

​ 2、将第一个元素和最后一个元素交换,也就是将根结点的元素和堆中最后一个元素交换,将堆的长度减一;

​ 3、重新对堆进行维护;

​ 4、重复2和3直到堆的长度变为0截至。

​ 堆排序中最关键的就是堆的维护工作,堆的维护就是利用递归不断比较根结点和子结点的元素大小,从底部向上将符合条件的元素上升到相应的根结点中。

​ 如下如图为一个大根堆的建立过程:

大根堆的建立过程

​ 上图可能不是很具有代表性,因为元素交换也可能造成结点和子结点之间的关系不符合堆的特性。下面有相关代码可以自己进行调试完整理解相关的算法执行过程。

​ 排序示意图:

堆排序的过程图

堆排序的效率

​ 堆排序是不稳定的排序算法,最坏情况下的时间复杂度为nlog2n

C语言代码

/***   堆排序算法(L为要进行排序的线性顺序表)*/typedef int type;void print_array(type *L, int len, char *msg);/***   用于交换元素*/void swap(type *a, type *b){    type tmp = *a;    *a = *b;    *b = tmp;}/***   L   为type类型的可进行大小对比的线性顺序表*   len 为线性顺序表的长度*//** *  维护堆的结构,大根堆 */void max_heap(type *L, int i, int len){    int max = 0;                                //保存最大值的下标    int left = 2 * i + 1;                       //本应为2i但是因为数组的起点为0因此要移位    int right = 2 * i + 2;    if (left < len && L[left] > L[i])    {        max = left;    }    else    {        max = i;    }    if (right < len && L[right] > L[max])    {        max = right;    }    if (i != max)    {        swap(&L[i], &L[max]);        max_heap(L, max, len);    }}/** *  构建堆,大根堆 */void build_heap(type *L, int len){    int i = 0;    for (i = len / 2; i >= 0; i--)    {        max_heap(L, i, len);    }}/** *  堆排序 */void heap_sort(type *L, int len){    int i = 0;    build_heap(L, len);    for (i = len - 1; i > 0; i--)    {        swap(&L[0], &L[i]);        max_heap(L, 0, i);    }}
0 0