堆排序_C

来源:互联网 发布:mac桌面时钟 编辑:程序博客网 时间:2024/06/17 09:12

 堆排序

 堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

  Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]    或者    Key[i]>=Key[2i+1]&&key>=key[2i+2]

 即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。

堆分为大顶堆和小顶堆:

满足 Key[i]>=Key[2i+1]&&key>=key[2i+2]      称为大顶堆。

满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]   称为小顶堆。

由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的

 算法思路:

假设 数组 a[ 8 ] = {Marks , 4, 6, 7, 5, 3, 8, 1};    (mask为占位符,无意义)  则由该数组生成的无序2叉树图如下:

                                                                                1(4)

                                                       

                                                           2(6)                             3(7)

 

                                              4(5)            5 (3)       6(8)          7(1)

 

声明一个函数从最后的  根节点  开始,(上图的第二层2,3为最后根节点)向上对2叉树进行排序。

1. 设数组大小为n(注意是不包括mask占位符的数组大小),从图上得最后一个根结为 n/2 = 3;(完全二叉树性质)

2. 得到当前要进行排序的根节点后,开始对该节点进行排序,对比该节点的  左    右 子节点的大小。 图中对应 比较 8    和  1 的大小。

3. 获得左右子较大者与父节点进行比较。图中对于比较   7 和 8, 若比父节点大则交换该值。

1,2,3 后

                                                                                  1(4)

 

                                                              2(6)                              3(8)

 

                                                   4(5)          5 (3)        6(7)              7(1)

接着对节点2 排序

 

                                                                                      1(4)

 

                                                               2(6)                                3(8)

 

                                                   4(5)            5 (3)       6(7)             7(1)

                                                                           (无变化)

 

然后开始对 节点1 排序   经过对 2, 3 节点比较交换后

                                                                              1(8)

                                                              2(6)                      3(4)

                                                   4(5)          5 (3)     6(7)    7(1)

 

4.   发现  3节点  比  6节点   小。将当前节点设置为3 继续进行比较交换。

 

                                                                              1(8)

                                                              2(6)                      3(7)

                                                   4(5)          5 (3)     6(4)    7(1)

符合堆定义了、完成排序。

 

 二。

接着开始交换数组元素,将堆顶元素与数组最后一个元素交换,然后对n-1大小的数组进行调整(节点7位置固定了,已经排除在调整的范围之外)

                                                                              1(1)

                                                              2(6)                      3(7)

                                                   4(5)          5 (3)     6(4)   7(8)

 

重复以上操作,直达数组交换完。

 

实现代码:

#include <stdio.h>#define MARKS 0void heap(int a[], int n);void adjust(int a[], int i, int n);int main(){    int i;    int a[7] = {MARKS,4,6,7,5,3,1};    printf("原数据:");    for (i = 1; i < 7; i++)    printf("%5d", a[i]);    heap(a, 6);    printf("\n处理后的数据:");    for (i = 1; i < 7; i++)    printf("%5d", a[i]);    return 0;}//void heap(int a[], int n){    int i,j,t;    for (i = n/2; i >0; i--)    {        adjust(a,i,n);    }    printf("\n初始化堆 ====>  ");    for (i = 1; i < n; i++)    {        printf("%5d", a[i]);    }    int count = 1;    for (i = n - 1; i > 0; i--)   // 交换值    {        t = a[i+1];        a[i+1] = a[1];        a[1] = t;        adjust(a,1,i);        printf("\n第 %5d 操作后的结果==>", count++);        for (j = 1; j < n; j++)        {            printf ("%5d", a[j]);        }    }}// 将第i个节点变成堆    n为数组长度void adjust(int a[], int i, int n){    int k ,r;    k = r = a[i];    int j = 2*i;    while (j <= n)    {        if (j < n)        {            if (a[j] < a[j+1])            j++;        }        if (k>= a[j])   // 比较父节点与子节点的大小 对于步骤 2        break;        else        {            a[j/2] = a[j];  // 交换值 注意不一定是父节点与子节点交换 对应步骤3            j = j * 2;      // 深入到子节点,将子节点设为当前节点   对应步骤4        }    }    a[j/2] = r;             // 比较完该父节点一下的子节点以及子节点的以下的节点                            //  或者父节点的值比子节点的大(子节点已经排好序了程序是自下向上进行排序)}




运行结果: