• 【数据结构】二叉树--堆排序


    目录

    一 降序(建小堆)

    二 升序 (建大堆)

    三 优化(以升序为例)

    四 TOP-K问题


    一 降序(建小堆)

    1. void Swap(int* x, int* y)
    2. {
    3. int tmp = *x;
    4. *x = *y;
    5. *y = tmp;
    6. }
    7. //降序 建小堆
    8. void AdjustUp(int* a, int child)
    9. {
    10. int parent = (child - 1) / 2;
    11. while (child > 0)
    12. {
    13. if (a[child] < a[parent])
    14. {
    15. Swap(&a[child], &a[parent]);
    16. child = parent;
    17. parent = (child - 1) / 2;
    18. }
    19. else
    20. {
    21. break;
    22. }
    23. }
    24. }
    25. void AdjustDown(int* a, int n, int parent)
    26. {
    27. int child = parent * 2 + 1;
    28. while (child < n)
    29. {
    30. if (child + 1 < n && a[child + 1] < a[child])
    31. {
    32. child++;
    33. }
    34. if (a[child] < a[parent])
    35. {
    36. Swap(&a[child], &a[parent]);
    37. parent = child;
    38. child = parent * 2 + 1;
    39. }
    40. else
    41. {
    42. break;
    43. }
    44. }
    45. }
    46. void HeapSort(int* a, int n)
    47. {
    48. int end = n - 1;
    49. int i = 0;
    50. //建堆
    51. for (i = 1; i < n; i++)
    52. {
    53. AdjustUp(a, i);
    54. }
    55. while (end > 0)
    56. {
    57. Swap(&a[0], &a[end]);
    58. AdjustDown(a, end, 0);
    59. end--;
    60. }
    61. }
    62. int main()
    63. {
    64. int a[] = { 2, 3, 5, 7, 4, 6, 8 };
    65. HeapSort(a, sizeof(a) / sizeof(int));
    66. return 0;
    67. }

    二 升序 (建大堆)

    1. //升序 建大堆
    2. void AdjustUp(int* a, int child)
    3. {
    4. int parent = (child - 1) / 2;
    5. while (child > 0)
    6. {
    7. if (a[child] > a[parent])
    8. {
    9. Swap(&a[child], &a[parent]);
    10. child = parent;
    11. parent = (child - 1) / 2;
    12. }
    13. else
    14. {
    15. break;
    16. }
    17. }
    18. }
    19. void AdjustDown(int* a, int n, int parent)
    20. {
    21. int child = parent * 2 + 1;
    22. while (child < n)
    23. {
    24. if (child + 1 < n && a[child + 1] > a[child])
    25. {
    26. child++;
    27. }
    28. if (a[child] > a[parent])
    29. {
    30. Swap(&a[child], &a[parent]);
    31. parent = child;
    32. child = parent * 2 + 1;
    33. }
    34. else
    35. {
    36. break;
    37. }
    38. }
    39. }
    40. void HeapSort(int* a, int n)
    41. {
    42. int end = n - 1;
    43. int i = 0;
    44. //建堆
    45. for (i = 1; i < n; i++)
    46. {
    47. AdjustUp(a, i);
    48. }
    49. while (end > 0)
    50. {
    51. Swap(&a[0], &a[end]);
    52. AdjustDown(a, end, 0);
    53. end--;
    54. }
    55. }
    56. int main()
    57. {
    58. int a[] = { 2, 3, 5, 7, 4, 6, 8 };
    59. HeapSort(a, sizeof(a) / sizeof(int));
    60. return 0;
    61. }

    三 优化(以升序为例)

    可以用向下建堆的方法

    1. void AdjustDown(int* a, int n, int parent)
    2. {
    3. int child = parent * 2 + 1;
    4. while (child < n)
    5. {
    6. if (child + 1 < n && a[child + 1] > a[child])
    7. {
    8. child++;
    9. }
    10. if (a[child] > a[parent])
    11. {
    12. Swap(&a[child], &a[parent]);
    13. parent = child;
    14. child = parent * 2 + 1;
    15. }
    16. else
    17. {
    18. break;
    19. }
    20. }
    21. }
    22. //void HeapSort(int* a, int n)
    23. //{
    24. // int end = n - 1;
    25. // int i = 0;
    26. // //建堆
    27. // for (i = 0; i < n; i++)
    28. // {
    29. // AdjustUp(a, i);
    30. // }
    31. //
    32. // while (end > 0)
    33. // {
    34. // Swap(&a[0], &a[end]);
    35. // AdjustDown(a, end, 0);
    36. // end--;
    37. // }
    38. //}
    39. void HeapSort(int* a, int n)
    40. {
    41. int end = n - 1;
    42. int i = 0;
    43. //建大堆
    44. for (i = (n-1-1) / 2; i >= 0; i--)
    45. {
    46. AdjustDown(a, n, i);
    47. }
    48. while (end > 0)
    49. {
    50. Swap(&a[0], &a[end]);
    51. AdjustDown(a, end, 0);
    52. end--;
    53. }
    54. }
    55. int main()
    56. {
    57. int a[] = { 2, 3, 5, 7, 4, 6, 8, 65, 100, 70, 32, 50, 60};
    58. HeapSort(a, sizeof(a) / sizeof(int));
    59. return 0;
    60. }

     

    这样建堆的方式对时间复杂度有什么优化吗?

     

    TOP-K问题

    TOP - K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

    比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

    对于Top - K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:1. 用数据集合中前K个元素来建堆

        前k个最大的元素,则建小堆

        前k个最小的元素,则建大堆

    2. 用剩余的N - K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

    将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

    1. #include
    2. #include
    3. #include
    4. typedef int HPDataType;
    5. void Swap(HPDataType* p1, HPDataType* p2)
    6. {
    7. HPDataType tmp = *p1;
    8. *p1 = *p2;
    9. *p2 = tmp;
    10. }
    11. void AdjustDown(HPDataType* a, int n, int parent)
    12. {
    13. int child = parent * 2 + 1;
    14. while (child < n)
    15. {
    16. if (child + 1 < n && a[child + 1] < a[child])
    17. {
    18. child++;
    19. }
    20. if (a[child] < a[parent])
    21. {
    22. Swap(&a[child], &a[parent]);
    23. parent = child;
    24. child = parent * 2 + 1;
    25. }
    26. else
    27. {
    28. break;
    29. }
    30. }
    31. }
    32. void PrintTopK(const char* filename, int k)
    33. {
    34. //1 建堆--用a中前K个元素建堆(小堆)
    35. FILE* fout = fopen(filename, "r");
    36. if (fout == NULL)
    37. {
    38. perror("fopen fail");
    39. return;
    40. }
    41. int* minheap = (int*)malloc(sizeof(int) * k);
    42. if (minheap == NULL)
    43. {
    44. perror("malloc fail");
    45. return;
    46. }
    47. for (int i = 0; i < k; i++)
    48. {
    49. fscanf(fout, "%d", &minheap[i]);
    50. }
    51. //前K个建小堆
    52. for (int i = (k-2) / 2; i >= 0; i--)
    53. {
    54. AdjustDown(minheap, k, i);
    55. }
    56. //2 将剩余n-k元素与堆顶元素比较, 满足就交换
    57. int x = 0;
    58. while (fscanf(fout, "%d", &x) != EOF)
    59. {
    60. if (x > minheap[0])
    61. {
    62. //替换进堆
    63. minheap[0] = x;
    64. AdjustDown(minheap, k, 0);
    65. }
    66. }
    67. for (int i = 0; i < k; i++)
    68. {
    69. printf("%d ", minheap[i]);
    70. }
    71. printf("\n");
    72. fclose(fout);
    73. }
    74. void CreateDate()
    75. {
    76. //造数据
    77. int n = 100000;
    78. srand(time(0));
    79. const char* file = "data.txt";
    80. FILE* fin = fopen(file, "w");
    81. if (fin == NULL)
    82. {
    83. perror("fopen error");
    84. return;
    85. }
    86. for (int i = 0; i < n; i++)
    87. {
    88. int x = (rand() + i) % n;
    89. fprintf(fin, "%d\n", x);
    90. }
    91. fclose(fin);
    92. }
    93. int main()
    94. {
    95. CreateDate();
    96. PrintTopK("data.txt", 5);
    97. return 0;
    98. }

     

    本节对前面的二叉树基础很高, 没有理解的, 可以翻看我之前对二叉树顺序结构及其实现的章节.

    继续加油! 

  • 相关阅读:
    5-爬虫-打码平台、打码平台自动登录打码平台、selenium爬取京东商品信息、scrapy介绍安装、scrapy目录结构
    GBase 8c 函数/存储过程定义
    离散事件仿真原理DES
    【MySQL系列】Java的JDBC编程
    C# 删除图片,不影响程序运行
    .NET Core多线 (5) 常见性能问题
    eazyexcel生成校验单元格内容的excel文件
    vue3学习实战
    umich cv-6-2 注意力机制
    longjmp导致局部变量丢失
  • 原文地址:https://blog.csdn.net/yf214wxy/article/details/133690881