• 数据结构 堆排序


    首先  了解一下堆排序的思想

    堆排序把数组看作是一个 完全二叉树  倒数第二层节点

    要么没有孩子

    要么只有一个孩子 

    要么有两个孩子

    假设当前节点的下标为i

    那么如果他有右孩子  右孩子的下标为2*i+2

    那么如果他有左孩子  左孩子的下标为2*i+1

    如果我们想把数组从小到大排序  那我们可以把二叉树假设成大根堆  :

    即  当前层的下一层的每一个节点的值都小于当前层的节点的值

    我们会通过调整让这个二叉树总是大根堆

    排序的方法 :

    经过调整

    最上面的节点总是最大的 

     我们让最大的这个节点和最后面的节点(最后一层的最右边的节点)交换 

    然后将最后的这个节点放入到数组中 

    同时将这个最后一个节点视为从二叉树上移除 

    继续调整二叉树   调整完  最上面的节点又是最大的了 

    但是没有开始移除的那个节点大  是第二大的  ....如此往复

    就直到二叉树中没有节点了  我们的数组也就排序好了

    我们的堆排序分为构建堆树   和  排序两个部分  组成 

    1. void HeapSort(int arr[], int nLen)
    2. {
    3. //参数校验
    4. if (arr == NULL || nLen <= 1)
    5. {
    6. return;
    7. }
    8. //构建堆树
    9. for (int i = nLen / 2 - 1; i >=0; i--)
    10. {
    11. //将树调整成大根堆
    12. Adjust(arr,nLen,i);
    13. }
    14. //排序
    15. for (int i = nLen - 1; i > 0; i--)//每次排完一个节点 二叉树中视为移除了一个节点
    16. {
    17. //顶部节点与最后一个节点交换
    18. arr[0] = arr[0] ^ arr[i];
    19. arr[i] = arr[0] ^ arr[i];
    20. arr[0] = arr[0] ^ arr[i];
    21. //再调整成大根堆(最上面的arr[0]是最大的节点)
    22. Adjust(arr, i, 0);
    23. }
    24. }

    其中 堆排序中用到的调整

    1. void Adjust(int arr[], int nLen, int index)
    2. {
    3. while (1)
    4. {
    5. if (2 * index + 2 < nLen)//两个孩子
    6. {
    7. //找到大的孩子
    8. int idex= arr[2 * index + 2] > arr[2 * index + 1] ? 2 * index + 2 : 2 * index + 1;
    9. //大孩子和当前节点比较
    10. //大孩子更大 交换
    11. if (arr[idex] > arr[index])
    12. {
    13. arr[index] = arr[idex] ^ arr[index];
    14. arr[idex] = arr[idex] ^ arr[index];
    15. arr[index] = arr[idex] ^ arr[index];
    16. index = idex;//以孩子为节点继续调整
    17. }
    18. //否则结束
    19. else
    20. break;
    21. }
    22. //一个孩子
    23. else if (2 * index + 1 < nLen)
    24. {
    25. int idex = 2 * index + 1;
    26. //和孩子就比较
    27. //比孩子小 交换
    28. if (arr[index] < arr[idex])
    29. {
    30. arr[index] = arr[idex] ^ arr[index];
    31. arr[idex] = arr[idex] ^ arr[index];
    32. arr[index] = arr[idex] ^ arr[index];
    33. }
    34. //比孩子大 结束
    35. else
    36. break;
    37. }
    38. //没孩子 结束
    39. else
    40. {
    41. break;
    42. }
    43. }
    44. }

    主函数中 我们定义了一个数组用来测试

      

    1. int arr[10] = { 9,8,7,6,5,4,3,3,1,0 };
    2. HeapSort(arr, 10);
    3. for (int val : arr)
    4. {
    5. cout << val << " ";
    6. }

    测试结果如下

     

    完整代码如下

    1. #include
    2. using namespace std;
    3. void Adjust(int arr[], int nLen, int index)
    4. {
    5. while (1)
    6. {
    7. if (2 * index + 2 < nLen)//两个孩子
    8. {
    9. //找到大的孩子
    10. int idex= arr[2 * index + 2] > arr[2 * index + 1] ? 2 * index + 2 : 2 * index + 1;
    11. //大孩子和当前节点比较
    12. //大孩子更大 交换
    13. if (arr[idex] > arr[index])
    14. {
    15. arr[index] = arr[idex] ^ arr[index];
    16. arr[idex] = arr[idex] ^ arr[index];
    17. arr[index] = arr[idex] ^ arr[index];
    18. index = idex;
    19. }
    20. //否则结束
    21. else
    22. break;
    23. }
    24. //一个孩子
    25. else if (2 * index + 1 < nLen)
    26. {
    27. int idex = 2 * index + 1;
    28. //和孩子就比较
    29. //比孩子小 交换
    30. if (arr[index] < arr[idex])
    31. {
    32. arr[index] = arr[idex] ^ arr[index];
    33. arr[idex] = arr[idex] ^ arr[index];
    34. arr[index] = arr[idex] ^ arr[index];
    35. }
    36. //比孩子大 结束
    37. else
    38. break;
    39. }
    40. //没孩子 结束
    41. else
    42. {
    43. break;
    44. }
    45. }
    46. }
    47. void HeapSort(int arr[], int nLen)
    48. {
    49. //参数校验
    50. if (arr == NULL || nLen <= 1)
    51. {
    52. return;
    53. }
    54. //构建堆树
    55. for (int i = nLen / 2 - 1; i >=0; i--)
    56. {
    57. Adjust(arr,nLen,i);
    58. }
    59. //排序
    60. for (int i = nLen - 1; i > 0; i--)
    61. {
    62. arr[0] = arr[0] ^ arr[i];
    63. arr[i] = arr[0] ^ arr[i];
    64. arr[0] = arr[0] ^ arr[i];
    65. //调整
    66. Adjust(arr, i, 0);
    67. }
    68. }
    69. int main()
    70. {
    71. int arr[10] = { 9,8,7,6,5,4,3,3,1,0 };
    72. HeapSort(arr, 10);
    73. for (int val : arr)
    74. {
    75. cout << val << " ";
    76. }
    77. return 0;
    78. }

  • 相关阅读:
    2023研究生数学建模D题思路
    项目实战:并发下保证接口的幂等性
    Vue 实现拖拽模块(二)自定义拖拽组件位置
    [Docker精进篇] Docker镜像构建和实践 (三)
    关于物联网你需要知道的一切
    CSS3常用的新功能总结
    深度学习笔记_5 经典卷积神经网络LeNet-5 解决MNIST数据集
    功率放大器是不是越大越好用
    【C语言】详解顺序表(SeqList)
    Java中的方法是什么?(Java系列2)
  • 原文地址:https://blog.csdn.net/van9527/article/details/126227143