zoukankan      html  css  js  c++  java
  • 堆排序 heap sort

    https://github.com/hotwater99/practice_datastructure_and_algorithm.git

    《数据结构与算法分析——C语言描述》机械工业出版社,原书第2版,7.5节


    可以参考这篇文章,有一步步的图解:

    https://blog.csdn.net/u010452388/article/details/81283998

    另外这个动图也可以帮助理解:

    https://www.jianshu.com/p/0d383d294a80

    1940317-9c37b4be1b7c96d1

    堆排序分为两步:

    1、把待排序的数组(N个元素)变成一个Max堆;

    2、数组分为两部分,前一部分为堆空间(初始大小N),后一部分为排序空间(初始大小0);

    3、取出堆顶的数,即堆空间的第一个数A[堆顶]与最后一个数B交换,堆空间-1,同时A进入排序空间(因为每次取出的都是堆中最大的数,交换后的位置也是连续的),排序空间+1;

    4、剩下的数再重新构造成Max堆,即将B在堆中下滤;

    5、最后得到的数组就变成了从小到大排列的有序数组。


    堆排序:

      1 #define LeftChild(i)    (2 * (i) + 1)
      2 
      3 void PercDown(int array[], int i, int N)
      4 {
      5   int child;
      6   int tmp;
      7 
      8   for (tmp = array[i]; LeftChild(i) < N; i = child) {
      9     child = LeftChild(i);
     10     if (child + 1 < N && array[child + 1] > array[child]) {
     11       child++;
     12     }
     13     if (tmp < array[child]) {
     14       array[i] = array[child];
     15     }
     16     else {
     17       break;
     18     }
     19   }
     20   array[i] = tmp;
     21 }
     22 
     23 void Swap(int *a, int *b)
     24 {
     25   int tmp = *a;
     26   *a = *b;
     27   *b = tmp;
     28 }
     29 
     30 void HeapSort(int array[], int N)
     31 {
     32   int i;
     33 
     34   // build heap
     35   for (i = N / 2; i >= 0; i--) {
     36     PercDown(array, i, N);
     37   }
     38   // delete max
     39   for (i = N - 1; i > 0; i--) {
     40     Swap(&array[0], &array[i]);
     41     PercDown(array, 0, i);
     42   }
     43 }

    void PercDown(int array[], int i, int N) 的功能是把array[i]这个元素下滤。

    构造Max堆:array[0]到array[N/2]将是非叶子节点,array[N/2]之后的将是叶子节点(不一定是在堆的最后一层,但都是叶子节点)。所以从非叶子节点开始处理,且从下往上,从右到左,即35行中i从N/2开始递减。

    删除最大数:交换堆顶array[0]--a和array[i]--b,堆顶a放到array[i],array[i]之后就不属于堆了,完成了从堆中删除最大数的操作,同时因为每次取出的都是堆中最大数,i也是从N-1开始递减,这样也完成了排序的工作;之后对b进行一次下滤操作,完成了重新构造Max堆的操作。


    完整代码:
      1 #include <iostream>
      2 #include <ctime>
      3 
      4 using namespace std;
      5 
      6 #define random(x)       (rand()%x)
      7 #define ARRAY_LENTH     100000
      8 
      9 #define LeftChild(i)    (2 * (i) + 1)
     10 
     11 void PercDown(int array[], int i, int N)
     12 {
     13   int child;
     14   int tmp;
     15 
     16   for (tmp = array[i]; LeftChild(i) < N; i = child) {
     17     child = LeftChild(i);
     18     if (child + 1 < N && array[child + 1] > array[child]) {
     19       child++;
     20     }
     21     if (tmp < array[child]) {
     22       array[i] = array[child];
     23     }
     24     else {
     25       break;
     26     }
     27   }
     28   array[i] = tmp;
     29 }
     30 
     31 void Swap(int *a, int *b)
     32 {
     33   int tmp = *a;
     34   *a = *b;
     35   *b = tmp;
     36 }
     37 
     38 void HeapSort(int array[], int N)
     39 {
     40   int i;
     41 
     42   // build heap
     43   for (i = N / 2; i >= 0; i--) {
     44     PercDown(array, i, N);
     45   }
     46   // delete max
     47   for (i = N - 1; i > 0; i--) {
     48     Swap(&array[0], &array[i]);
     49     PercDown(array, 0, i);
     50   }
     51 }
     52 
     53 int main() {
     54   int test_array[ARRAY_LENTH];
     55   int i, N = ARRAY_LENTH;
     56   clock_t start_time, stop_time;
     57 
     58   for (i = 0; i < N; i++) {
     59     test_array[i] = random(N);
     60   }
     61 
     62   cout << "raw : ";
     63   for (i = 0; i < N; i++) {
     64     cout << test_array[i] << " ";
     65   }
     66   cout << endl;
     67 
     68   start_time = clock();
     69 
     70   HeapSort(test_array, N);
     71 
     72   stop_time = clock();
     73 
     74   cout << "sort: " ;
     75   for (i = 0; i < N; i++) {
     76     cout << test_array[i] << " ";
     77   }
     78   cout << endl;
     79 
     80   cout << "HeapSort(" << N << ")..." << endl;
     81   cout << "total time used: ";
     82   cout  << (double)(stop_time - start_time) / CLOCKS_PER_SEC << "s" << endl;
     83 
     84   system("pause");
     85 
     86   return 0;
     87 }


    测试结果


    N=10

    raw : 1 7 4 0 9 4 8 8 2 4
    sort: 0 1 2 4 4 4 7 8 8 9
    HeapSort(10)...
    total time used: 0s

    N=100

    raw : 41 67 34 0 69 24 78 58 62 64 5 45 81 27 61 91 95 42 27 36 91 4 2 53 92 82 21 16 18 95 47 26 71 38 69 12 67 99 35 94 3 11 22 33 73 64 41 11 53 68 47 44 62 57 37 59 23 41 29 78 16 35 90 42 88 6 40 42 64 48 46 5 90 29 70 50 6 1 93 48 29 23 84 54 56 40 66 76 31 8 44 39 26 23 37 38 18 82 29 41
    sort: 0 1 2 3 4 5 5 6 6 8 11 11 12 16 16 18 18 21 22 23 23 23 24 26 26 27 27 29 29 29 29 31 33 34 35 35 36 37 37 38 38 39 40 40 41 41 41 41 42 42 42 44 44 45 46 47 47 48 48 50 53 53 54 56 57 58 59 61 62 62 64 64 64 66 67 67 68 69 69 70 71 73 76 78 78 81 82 82 84 88 90 90 91 91 92 93 94 95 95 99
    HeapSort(100)...
    total time used: 0s

    N=1000

    HeapSort(1000)...
    total time used: 0s

    N=10000

    HeapSort(10000)...
    total time used: 0.001s

    N=100000

    HeapSort(100000)...
    total time used: 0.017s
  • 相关阅读:
    Windows phone 墓碑机制的一些源码
    关于Image一些比较抽象的东西(Build Type与 同步以及异步加载的差异)
    自定义控件之Button控件的自定义
    Java集合最全解析,学集合,看这篇就够用了!!!
    看完让你彻底搞懂Websocket原理
    别人的前途我不敢决定
    花一年的时间让自己过得像个人样
    开篇
    你看得懂吗?
    反思
  • 原文地址:https://www.cnblogs.com/hotwater99/p/12800865.html
Copyright © 2011-2022 走看看