八大排序算法(4) 堆排序

来源:互联网 发布:电脑应用无法链接网络 编辑:程序博客网 时间:2024/05/04 20:21

基本思想

是对简单选择排序的改进,是一种树形结构的排序。
利用堆的特性,快速选择出序列中的最大最小元素。

堆的定义:
这里写图片描述

用树表示更加直观:
这里写图片描述
即:父节点 不大于/不小于 其子节点的完全二叉树。
降序时称为 大堆顶,升序时称为 小堆顶。

这样的堆,其堆顶就是整个序列中最大/最小的元素。
不断的取出堆顶、将剩下序列重组成堆的过程就叫堆排序。

树采用顺序存储:{96,83,27,38,11,09}, {12,36,24,85,47,30,53,91}
序列是树的顺序存储,因此 节点、父、子 在序列中的位置为 i,2i,2i+1, 反映到序列中的 index 为 i - 1, 2*i-1, 2*i。

重点

 1. 初始化时将整个序列转换成堆   2. 取出堆顶后,将剩下的元素快速组成堆

先说第二点的算法思路:

 1. 取出堆顶后 i 后,将堆底元素取出补为堆顶 2. 检查到堆被破坏,将 堆顶 与其子节点中小的元素交换 3. 对交换后的子树重复2

示例图:
这里写图片描述

再说第一点的算法思路:

 1. 假设 长度 n 的 序列 k 为堆 2. 最后一个节点是 节点 n/2 的子节点,那么从 n/2 开始向上筛选 3. 从 父子节点 中选举最小的为 父节点 4. 对交换后的子节点 重复 3,直到叶子节点 5. 检查下一个 n/2 - 1 ,重复 3, 直到 0

示例图:
这里写图片描述

代码:

void printList(int *l, int n) {    for (int i = 0; i < n; i++) {        printf("%d ", l[i]);    }    printf("\n");}/* * 修复堆 *  * 从 父子 节点中选举最小的为父节点。 * 如果最小的不是父节点的话,那么交换过的子节点也需要检查。 */void adjustHeap(int *l, int n, int topIndex, int adjustIndex) {    // 要检查的元素 index    int minIndex = adjustIndex;    // 堆顶不为 0 时,计算 adjustIndex 的子节点 index 要考虑到偏移    int lcIndex = 2 * (adjustIndex - topIndex + 1) - 1 + topIndex;    int rcIndex = 2 * (adjustIndex - topIndex + 1) + topIndex;    // 跟 左子节点比较,替换 小的 index    if (lcIndex < n && l[minIndex] > l[lcIndex] ){        minIndex = lcIndex;    }    // 跟 右子节点比较,替换 小的 index    if (rcIndex < n && l[minIndex] > l[rcIndex]){        minIndex = rcIndex;    }    // 如果小的index 不是 堆顶的话,那么换顶,然后检查子堆    if ( minIndex != adjustIndex ){        int k = l[minIndex];        l[minIndex] = l[adjustIndex];        l[adjustIndex] = k;        // 子堆 minIndex 换了 堆顶,要检查一下        adjustHeap(l, n, topIndex, minIndex);    }}/* * 创建堆 *  * 1、假设 长度 n 的 序列 k 为堆 * 2、最后一个节点为 n / 2 的子节点,从 n / 2 开始向上筛选 * 3、从 父子节点中选举最小的为 父节点 * 4、检查下一个 n / 2 - 1 ,重复 3, 直到 0 */void buildHeap(int *l, int n) {    for (int i = n / 2; i > 0;i-- ) {        // 节点 i 对应的 index 是 i - 1, 子节点 index  2 * i - 1、 2 * i        int min = i - 1;        int lc = 2 * i - 1;        int rc = 2 * i;        // 选举最小的为 堆顶        if (l[i - 1] > l[lc]){            min = lc;        }        if ( 2*i < n && l[min] > l[rc]){            min = rc;        }        if ( min != i-1 ) {            int k = l[i - 1];            l[i - 1] = l[min];            l[min] = k;            // 子堆 min 换了堆顶,要检查堆 min            adjustHeap(l, n, 0, min);        }    }}int main() {    int list[50] = { 10, 7, 1 , 8, 5, 12, 6, 3, 9 };    int n = 9;    printList(list, n);    // 创建小堆顶    buildHeap(list, n);    printList(list, n);    printf("======\n");    // 建好堆后,初始堆顶就是最小的    for (int i = n - 1; i > 0; i--) {        //将堆顶换到堆底.  这是小堆顶,每次都将最小的元素换到堆底,然后 堆缩小 1,最后得出降序        int exchange = list[0];        list[0] = list[i];        list[i] = exchange;        // 堆 0 被破坏,执行检查        adjustHeap(list, i, 0, 0);        printList(list, n);    }    system("pause");    return 0;}

以上

原文链接 http://blog.csdn.net/u011546766/article/details/74045324

原创粉丝点击