• 堆排序和优先队列


    目录

    一:什么是堆

    二:最大堆的代码实现 

     构造函数+析构函数

    核心函数---入堆和出堆

    构造函数之:用数组构造堆 

    两种构造函数分别对应了两个堆排序 

    完整程序 

    原地堆排序


    一:什么是堆

    最大堆

    结构上是一颗完全二叉树

    数值上要求:父节点的值>=其孩子节点的值

    二:最大堆的代码实现 

    因为堆是完全二叉树的结构,所以用动态数组去存储最大堆。

    1. template<class Type>
    2. class maxHeap{
    3. private:
    4. Type* data;
    5. int maxSize;
    6. int curSize;
    7. void doublespace(){
    8. Type* tmp=data;
    9. maxSize*=2;
    10. data=new Type[maxSize];
    11. for(int i=1;i<=curSize;i++){
    12. data[i]=tmp[i];
    13. }
    14. delete[] tmp;
    15. }
    16. };

     构造函数+析构函数

    1. public:
    2. //构造函数
    3. maxHeap(int initsize=5){
    4. data=new Type[initsize+1];//堆从1开始存储
    5. maxSize=initsize;
    6. curSize=0;
    7. }
    8. //用数组构造
    9. template<typename T>
    10. maxHeap(T a[],int n);
    11. //析构函数
    12. ~maxHeap(){ delete[] data;}

    核心函数---入堆和出堆

     入堆

    1. //入堆
    2. template<class Type>
    3. void maxHeap<Type>::shiftUp(int k){
    4. Type e=data[k];
    5. for(k;k>1 && data[k/2]<e;k/=2){//根节点之前
    6. data[k]=data[k/2];
    7. }
    8. data[k]=e;
    9. }
    10. template<class Type>
    11. void maxHeap<Type>::enHeap(const Type& x){
    12. if(curSize==maxSize-1) doublespace();
    13. data[++curSize]=x;
    14. shiftUp(curSize);
    15. }

    思路:

    把元素放入当前堆长度的后一个位置,然后为了维护堆的结构性,进行向上调整

    注意----从1开始存储时,数组第k个位置的结点,其父节点k/2,其左孩子k*2,右孩子k*2+1

    出堆 

    1. //入堆
    2. template<class Type>
    3. void maxHeap<Type>::shiftUp(int k){
    4. Type e=data[k];
    5. for(k;k>1 && data[k/2]<e;k/=2){//根节点之前
    6. data[k]=data[k/2];
    7. }
    8. data[k]=e;
    9. }
    10. template<class Type>
    11. void maxHeap<Type>::enHeap(const Type& x){
    12. if(curSize==maxSize-1) doublespace();
    13. data[++curSize]=x;
    14. shiftUp(curSize);
    15. }

    堆是优先级队列,所以根节点出堆,然后把当前堆的最后一个结点放到根节点,数组长度-1,然后从根节点进行向下调整。

    向下调整步骤:

    • 循环前提:当前结点k至少有左孩子(k*2<=数组长度)
    • 用j来记录左右孩子最大值:k的右孩子存在然后比较左右孩子数值取最大(if条件)
    • 然后判断是否要调整:即---把左右孩子最大值和父节点判断,维护最大堆
    • 更新k=j,然后继续循环

    构造函数之:用数组构造堆 

    1. //用数组构造
    2. template<typename T>
    3. maxHeap(T a[],int n){
    4. //注意:成员变量初始化
    5. maxSize=n+1;
    6. curSize=n;
    7. data=new Type[maxSize];
    8. for(int i=1;i<=n;i++){
    9. data[i]=a[i-1];
    10. }
    11. //从最后一个非叶子结点,逐个向下调整
    12. for(int j=n/2;j>=1;j--){//根节点也要进行,堆为1
    13. shiftDown(j);
    14. }
    15. }

     思路:

    把数组值依次存入堆数组,然后从第一个非叶子结点逐次遍历到根节点,每次都执行向下调整。注意:从1存放的堆的第一个非叶子结点是curSize/2

    两种构造函数分别对应了两个堆排序 

    1. template<typename T>
    2. void heapSort_one(T a[],int n){
    3. maxHeap<int> heap;
    4. for(int i=0;i<n;i++){
    5. heap.enHeap(a[i]);
    6. }
    7. for(int i=n-1;i>=0;i--){
    8. a[i]=heap.deHeap();
    9. }
    10. }
    1. template<typename T>
    2. void heapSort_arr(T a[],int n){
    3. maxHeap<int> heap(a,n);
    4. for(int i=n-1;i>=0;i--){
    5. a[i]=heap.deHeap();
    6. }
    7. }

    完整程序 

    maxheap.h 

    1. #ifndef my_Maxheap
    2. #define my_Maxheap
    3. template<class Type>
    4. class maxHeap{
    5. private:
    6. Type* data;
    7. int maxSize;
    8. int curSize;
    9. void doublespace(){
    10. Type* tmp=data;
    11. maxSize*=2;
    12. data=new Type[maxSize];
    13. for(int i=1;i<=curSize;i++){
    14. data[i]=tmp[i];
    15. }
    16. delete[] tmp;
    17. }
    18. //辅助函数---向上调整和向下调整
    19. void shiftUp(int k);
    20. void shiftDown(int k);
    21. public:
    22. //构造函数
    23. maxHeap(int initsize=5){
    24. data=new Type[initsize+1];//堆从1开始存储
    25. maxSize=initsize;
    26. curSize=0;
    27. }
    28. template<typename T>
    29. maxHeap(T a[],int n){
    30. //注意:成员变量初始化
    31. maxSize=n+1;
    32. curSize=n;
    33. data=new Type[maxSize];
    34. for(int i=1;i<=n;i++){
    35. data[i]=a[i-1];
    36. }
    37. //从最后一个非叶子结点,逐个向下调整
    38. for(int j=n/2;j>=1;j--){//根节点也要进行,堆为1
    39. shiftDown(j);
    40. }
    41. }
    42. //析构函数
    43. ~maxHeap(){ delete[] data;}
    44. //核心函数:入堆和出堆
    45. void enHeap(const Type& x);//堆是优先队列,所以放置后面,向上调整
    46. Type deHeap();//根节点出堆,向下调整
    47. };
    48. //入堆
    49. template<class Type>
    50. void maxHeap<Type>::shiftUp(int k){
    51. Type e=data[k];
    52. for(;k>1 && data[k/2]<e;k/=2){//根节点之前
    53. data[k]=data[k/2];
    54. }
    55. data[k]=e;
    56. }
    57. template<class Type>
    58. void maxHeap<Type>::enHeap(const Type& x){
    59. if(curSize==maxSize-1) doublespace();
    60. data[++curSize]=x;
    61. shiftUp(curSize);
    62. }
    63. //出堆
    64. template<class Type>
    65. void maxHeap<Type>::shiftDown(int k){
    66. Type e=data[k];
    67. int j;
    68. while(k*2<=curSize){//左孩子存在
    69. j=k*2;
    70. if(j+1<=curSize && data[j+1]>data[j]) j+=1;//取左右孩子最大值
    71. //判断:根节点和max(左右孩子)
    72. if(data[j]> e) data[k]=data[j];
    73. else break;
    74. //更新k值
    75. k=j;
    76. }
    77. data[k]=e;
    78. }
    79. template<class Type>
    80. Type maxHeap<Type>::deHeap(){
    81. Type x=data[1];
    82. data[1]=data[curSize--];
    83. shiftDown(1);
    84. return x;
    85. }
    86. #endif

    sortHelper.h 

    1. #include<ctime>
    2. #include<cassert>
    3. #include<iostream>
    4. #include"maxheap.h"
    5. using namespace std;
    6. namespace sortHelper{
    7. //生成数组
    8. template<typename T>
    9. T* gen_ran_arr(int n,int L,int R){
    10. assert(L<=R);
    11. srand(time(NULL));
    12. T* arr=new T[n];
    13. for(int i=0;i<n;i++){
    14. arr[i]=rand()%(R-L)+1;
    15. }
    16. return arr;
    17. }
    18. //打印数组
    19. template<typename T>
    20. void arr_print(T a[],int n){
    21. for(int i=0;i<n;i++){
    22. cout<<a[i]<<" ";
    23. }
    24. cout<<endl;
    25. }
    26. /*堆排序*/
    27. template<typename T>
    28. void heapSort_one(T a[],int n){
    29. maxHeap<int> heap;
    30. for(int i=0;i<n;i++){
    31. heap.enHeap(a[i]);
    32. }
    33. for(int i=n-1;i>=0;i--){
    34. a[i]=heap.deHeap();
    35. }
    36. }
    37. template<typename T>
    38. void heapSort_arr(T a[],int n){
    39. maxHeap<int> heap(a,n);
    40. for(int i=n-1;i>=0;i--){
    41. a[i]=heap.deHeap();
    42. }
    43. }
    44. }

    原地堆排序

    原地堆排序-----直接在原数组进行堆排序,不额外申请空间,因而序号也是0开始

    在0开始的数组中:

    • 结点k的父节点(k-1)/2,左孩子:2*k+1,右孩子2*k+2
    • n个结点的堆中最后一个非叶子结点:(n-1)/2
    1. template<typename T>
    2. void shiftDown_yuandi(T a[],int n,int k){
    3. T e=a[k];
    4. int j;
    5. while(k*2+1<n){
    6. j=k*2+1;
    7. if(j+1<n && a[j+1]>a[j]) j+=1;
    8. if(a[j]>e) a[k]=a[j];
    9. else break;
    10. k=j;
    11. }
    12. a[k]=e;
    13. }
    14. template<typename T>
    15. void heapSort_yuandi(T a[],int n){
    16. //原数组先调整成堆
    17. for(int i=(n-1)/2;i>=0;i--){
    18. shiftDown_yuandi(a,n,i);
    19. }
    20. //把堆顶元素后移,依次再调整成堆
    21. for(int i=n-1;i>0;i--){
    22. swap(a[0],a[i]);
    23. shiftDown_yuandi(a,i,0);
    24. }
    25. }

    注意---不要讲j定义在while外

  • 相关阅读:
    React18+Redux+antd 项目实战 JS
    跟TED演讲学英文:Entertainment is getting an AI upgrade by Kylan Gibbs
    Spring漏洞综合利用
    selinux-policy-default(2:2.20231119-2)软件包内容详细介绍(1)
    utm 转 经纬度坐标 cesium Ue4 CityEngine
    【问题记录】如何查找服务器的 cuda 环境变量 TORCH_CUDA_ARCH_LIST
    SpringCloud 分布式锁与分布式事务
    工匠的发展与兴衰趋势-机器人篇
    OpenGL之光照贴图
    Android codec2 视频框架 之应用
  • 原文地址:https://blog.csdn.net/weixin_47173597/article/details/125548403