• 堆排序算法和Topk思想


    目录

    1>>导言

    2>>堆排序

    2.1>>通过堆结构实现堆排序

    2.2>>堆思想实现排序

    3>>Topk思想

    4>>代码

    5>>结语


    1>>导言

            今天重点内容就是带着大家实现堆排序和Topk,堆排序分为两种,一种是直接调用堆的数据结构来实现的,另一种就是通过堆的思想实现的,Topk就是在一个数组中寻找前k个最大/最小的数,通常利用在世界五百强企业、十大富豪等等。

    2>>堆排序

    2.1>>通过堆结构实现堆排序

    1.首先给了一个数组,我们需要统计出它的大小。

    2.创建一个堆结构变量hp,并且初始化它。注意:传的是地址

    3.往这个堆中传递arr数组的每个数

    4.循环判断,当堆不为空时,每次取根节点,然后删除根节点(删除操作还记得叭?就是讲最后结点和根结点互换,然后size--,就可以将最后一个结点删除,然后将新的根结点向下调整)

    5.每次取出的头结点(根据大堆就是最大,小堆就是最小),所以最终就是一个降序/升序啦!

    这边以大根堆为结果,宝子们可以去试试噢

    2.2>>堆思想实现排序

    1.要实现堆排序,首先得要是一个堆,那么第一个循环就要把堆建立,双亲结点向下调整思想,从最后一个结点的双亲结点开始(最后一个结点是n-1)它的双亲结点是-1然后除2,依次向下调整,这样就是一个堆。

    2.将这个棵树的每一个子树都想象成一个堆,然后:

    3.从最后一个结点开始,到0为止,每次交换它的最后一个结点和第0个结点,然后向下调整,这样就能够从大/从小排序

    问题:要实现升序建(大堆/小堆)?要实现降序建(大堆/小堆)?

    答案是:升序建大堆,降序建小堆,因为升序每次交换将最大的移到最后面了所以要大堆。

    这是最终结果

    3>>Topk思想

    首先我们来造一个空间为100000的文件,通过之前章节学的随机数初始化文件每个数值

    srand表示更改随机数初始值

    创建一个file的文件,存放字符指针,叫data.txt

    通过fopen打开文件file,w表示写入,若返回不为空则开始往变量fin写数据

    最后关闭文件。

    上面步骤稍微过一遍,现在开始实现topk,这才是重点

    1. void TopK()
    2. {
    3. int k = 0;
    4. printf("请输入K:");
    5. scanf("%d", &k);
    6. const char* file = "data.txt";
    7. FILE* fout = fopen(file, "r");
    8. if (fout == NULL)
    9. {
    10. perror("fopen error");
    11. exit(1);
    12. }
    13. //找最大的前K个数,建小堆
    14. int* minHeap = (int*)malloc(sizeof(int) * k);
    15. if (minHeap == NULL)
    16. {
    17. perror("malloc fail!");
    18. exit(2);
    19. }
    20. //读取文件中前K个数据建堆
    21. for (int i = 0; i < k; i++)
    22. {
    23. fscanf(fout, "%d", &minHeap[i]);
    24. }
    25. // 建堆
    26. for (int i = (k - 1 - 1) / 2; i >= 0; i--) {
    27. adjustdown(minHeap, i, k);
    28. }
    29. //要最大就建小堆,要最小就键大堆
    30. int x = 0;
    31. while (fscanf(fout, "%d", &x) != EOF) {
    32. if (x > minHeap[0]) {
    33. minHeap[0] = x;
    34. adjustdown(minHeap, 0, k);
    35. }
    36. }
    37. for (int i = 0; i < k; i++) {
    38. printf("%d ", minHeap[i]);
    39. }
    40. }

    输入指定空间/堆大小k,然后读取文件每组数字,要找最大的前k个数,就要建小堆,就跟我们要最大值取最小值min一样的,若返回不为空,那么开始建堆,取前k个数据,建堆,跟建堆思想一样,从最后一个结点的父节点开始,依次向下调整,最后循环遍历文件的每一个数,如果读取到的数数大于我们的根结点,那么另根结点等于它,然后依次向下调整即可

    这是文件中的数

    4>>代码

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"heap.h"
    3. void test()
    4. {
    5. HP hp;
    6. hpinit(&hp);
    7. hppush(&hp, 1);
    8. hppush(&hp, 2);
    9. hppush(&hp, 4);
    10. hppush(&hp, 5);
    11. hppop(&hp);
    12. hppop(&hp);
    13. hppop(&hp);
    14. hpdestroy(&hp);
    15. }
    16. void test1() {
    17. int arr[] = { 17,20,10,13,19,15 };
    18. int n = sizeof(arr) / sizeof(arr[0]);
    19. HP hp;
    20. hpinit(&hp);
    21. int i = 0;
    22. for (i = 0; i < n; i++) {
    23. hppush(&hp, arr[i]);
    24. }
    25. i = 0;
    26. while (!hpempty(&hp)) {
    27. arr[i++] = hptop(&hp);
    28. hppop(&hp);
    29. }
    30. for (i = 0; i < n; i++) {
    31. printf("%d ", arr[i]);
    32. }
    33. }
    34. void HeapSort(int* arr, int n) {//自己实现堆排序
    35. for (int i =(n-1-1)/2; i >= 0; i--) {
    36. adjustdown(arr, i, n);
    37. }
    38. int end = n - 1;//最后一个结点开始,到0 为止
    39. while (end) {//大根堆
    40. swap(&arr[0], &arr[end]);
    41. adjustdown(arr, 0, end);//end一直--;
    42. end--;
    43. }
    44. //大根堆为升序
    45. }
    46. void CreateNDate()
    47. {
    48. // 造数据
    49. int n = 100000;
    50. srand((unsigned int)time(0));
    51. const char* file = "data.txt";
    52. FILE* fin = fopen(file, "w");
    53. if (fin == NULL)
    54. {
    55. perror("fopen error");
    56. return;
    57. }
    58. for (int i = 0; i < n; ++i)
    59. {
    60. int x = (rand() + i) % 1000000;
    61. fprintf(fin, "%d\n", x);
    62. }
    63. fclose(fin);
    64. }
    65. void TopK()
    66. {
    67. int k = 0;
    68. printf("请输入K:");
    69. scanf("%d", &k);
    70. const char* file = "data.txt";
    71. FILE* fout = fopen(file, "r");
    72. if (fout == NULL)
    73. {
    74. perror("fopen error");
    75. exit(1);
    76. }
    77. //找最大的前K个数,建小堆
    78. int* minHeap = (int*)malloc(sizeof(int) * k);
    79. if (minHeap == NULL)
    80. {
    81. perror("malloc fail!");
    82. exit(2);
    83. }
    84. //读取文件中前K个数据建堆
    85. for (int i = 0; i < k; i++)
    86. {
    87. fscanf(fout, "%d", &minHeap[i]);
    88. }
    89. // 建堆
    90. for (int i = (k - 1 - 1) / 2; i >= 0; i--) {
    91. adjustdown(minHeap, i, k);
    92. }
    93. //要最大就建小堆,要最小就键大堆
    94. int x = 0;
    95. while (fscanf(fout, "%d", &x) != EOF) {
    96. if (x > minHeap[0]) {
    97. minHeap[0] = x;
    98. adjustdown(minHeap, 0, k);
    99. }
    100. }
    101. for (int i = 0; i < k; i++) {
    102. printf("%d ", minHeap[i]);
    103. }
    104. }
    105. int main()
    106. {
    107. /*test();*/
    108. //test1();
    109. //int arr[] = { 17,20,10,13,19,15 };
    110. //int n = sizeof(arr) / sizeof(arr[0]);
    111. //HeapSort(arr, n);
    112. //
    113. //int i;
    114. //for (i = 0; i < n; i++) {
    115. // printf("%d ", arr[i]);
    116. //}
    117. //CreateNDate();
    118. TopK();
    119. return 0;
    120. }
    1. #include"heap.h"
    2. void hpinit(HP* php) {
    3. assert(php);
    4. php->arr = NULL;
    5. php->size = php->capacity = 0;
    6. }
    7. bool hpempty(HP* php) {
    8. assert(php);
    9. return php->size==0;
    10. }
    11. int hpsize(HP* php) {
    12. assert(php);
    13. return php->size;
    14. }
    15. void adjustup(hpdatatype* arr, int child) {
    16. //向上调整,parent为(child-1)/2; leftchild为parent*2+1,rightchild为parent*2+2
    17. int parent = (child - 1) / 2;
    18. //为根结点即为0结束
    19. while (child > 0) {
    20. //小根堆<,从上往下每个子孙都比我大
    21. //大根堆>,从上往下每个子孙都比我小
    22. if (arr[child] > arr[parent]) {
    23. //两数交换
    24. swap(&arr[child], &arr[parent]);
    25. //孩子和双亲结点往上走
    26. child = parent;
    27. parent = (child - 1) / 2;
    28. }
    29. else {
    30. break;
    31. }
    32. }
    33. }
    34. void hppush(HP* php, hpdatatype x) {
    35. assert(php);
    36. //空间不够就扩容,与顺序表一致
    37. if (php->size==php->capacity)
    38. {
    39. int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
    40. hpdatatype* tmp = (hpdatatype*)realloc(php->arr, newcapacity * sizeof(hpdatatype));
    41. if (tmp == NULL) {
    42. perror("realloc");
    43. exit(1);
    44. }
    45. php->arr = tmp;
    46. php->capacity = newcapacity;
    47. }
    48. //扩容结束
    49. //存放数据,每次存放就要比较,以小根堆为例子
    50. //0 1 2 3 size为4,新加入的数据下标为size
    51. php->arr[php->size] = x;
    52. //加入的不一定是与祖先比较大的数,因此需要向上调整
    53. adjustup(php->arr, php->size);
    54. //交换完毕size++
    55. php->size++;
    56. }
    57. void adjustdown(hpdatatype* arr, int parent,int size) {
    58. //向下调整,leftchild为parent*2+1,rightchild为parent*2+2
    59. int child = parent * 2 + 1;
    60. //大于等于总结个数n即为size结束
    61. while (child
    62. //小根堆,从上往下每个子孙都比我大
    63. //大根堆,从上往下每个子孙都比我小
    64. //此时用小根堆
    65. //先要判断左孩子和右孩子哪个更小
    66. if (child + 1 < size && arr[child] > arr[child + 1]) {
    67. child++;
    68. }
    69. //两数交换
    70. //孩子和双亲结点往下走
    71. if (arr[child] < arr[parent])
    72. {
    73. swap(&arr[child], &arr[parent]);
    74. parent = child;
    75. child = parent * 2 + 1;
    76. }
    77. else {
    78. break;
    79. }
    80. }
    81. }
    82. void hppop(HP* php) {
    83. assert(php);
    84. assert(!hpempty(php));
    85. //删除堆顶数据不能直接删除
    86. //否则会大乱套
    87. //思路:根屁股结点互换,然后让新的堆顶向下调整,size--
    88. //屁股为size-1;
    89. swap(&php->arr[0], &php->arr[php->size - 1]);
    90. php->size--;
    91. adjustdown(php->arr,0,php->size);
    92. }
    93. hpdatatype hptop(HP* php) {
    94. assert(php);
    95. return php->arr[0];
    96. }
    97. void swap(int* child, int* parent) {
    98. int tmp = *child;
    99. *child = *parent;
    100. *parent = tmp;
    101. }
    102. void hpdestroy(HP* php) {
    103. assert(php);
    104. assert(!hpempty(php));
    105. if (php->arr)
    106. free(php->arr);
    107. php->arr = NULL;
    108. php->size = php->capacity = 0;
    109. }

    5>>结语

            这篇讲的算法思想——堆排序和topk,希望对宝子们有所帮助,有不懂的欢迎评论区指出,也欢迎大佬们指点小编的文章,谢谢大家观看,期待与你下篇再见~

  • 相关阅读:
    李航《统计学习方法》笔记之k近邻法
    Web大学生网页作业成品——易购商城网站设计与实现(HTML+CSS+JavaScript)
    java -- abstract
    nodejs+vue养老人员活体鉴权服务系统elementui
    Spring @Valid @Validated实现验证的方法
    WebSocket实战之五JSR356
    如何解决bootstrap覆盖css样式的问题?
    使用PaddleNLP UIE模型提取上市公司PDF公告关键信息
    Linux vim 报错 E437
    【python】算法与数据结构例题
  • 原文地址:https://blog.csdn.net/m0_69282950/article/details/143249566