zoukankan      html  css  js  c++  java
  • 一个菜鸟对于堆排序的理解

    N个元素称为堆,若它的元素序列k[1],k[2],k[3]…K[n]满足

       k[i]<=k[2i]  ,k[i]<=k[2i+1]     1<=i<=n/2
    

    则称之为最小堆(min_heaps), 如果满足

      k[i]>=k[2i]  ,k[i]>=k[2i+1]     1<=i<=n/2
    

    则称之为最大堆(min_heaps)。

    用图来理解的话
    在这里插入图片描述
    图中对顶端的元素最大为大根堆,最小为小根堆(该图为大根堆)

    建立一个堆只需要将元素一个一个插入即可,自上而下建堆的时间复杂度为O(n*log2n)插入元素时需保证堆顶元素始终最大(最小),而自下而上的建堆方
    式是从第一个非叶子节点开始建堆,注意将最大(最小)元素交换到堆顶.
    下面是一个自上而下建堆的动态演示网站
    https://bajdcc.github.io/html/heap.html

    我们不难看出堆是无须的.
    堆得排序
    假设堆有n个元素,由于堆的第一个元素一定是最大的元素,因此可以让第一个元素和第n个元素互换,然后对第一个元素执行下操作。接着,对n-1个元素执行相同的操作,让第一个元素与第n-1个元素互换,然后对第一个元素执行下移操作,依次类推,最后的堆就是从小到大排序好的堆。

    void heap_sort(int *H,int m)
    {
    	for(int i=m;i>0;i--)
    	{
    		swap(H[i],H[1]);
    		sift_down(H,i-1,1); 
    	}
    }
    
    

    堆的插入
    插入到堆最后1个元素后面,然后对该元素执行上移操作

    堆的修改
    如果修改堆中某个元素,使得它的值大于父节点的,这就破坏了最大堆的性质,因此需要对堆实现上移操作。
    如果修改堆中某个元素,使得它的值小于孩子节点,这就破坏了最大堆的性质,因此需要对堆实现下移操作。

    堆的删除操作
    如果我们要删除下标为 i 的元素,那么我们可以用堆中最后1个元素替代i,然后对这个替代后的元素执行上移或者下移操作
    完整代码如下

     //构建大根堆:将array看成完全二叉树的顺序存储结构
          private int[] buildMaxHeap(int[] array){
              //从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆
              for(int i=(array.length-2)/2;i>=0;i--){ 
                  adjustDownToUp(array, i,array.length);
              }
              return array;
          }
          
         //将元素array[k]自下往上逐步调整树形结构
         private void adjustDownToUp(int[] array,int k,int length){
             int temp = array[k];   
             for(int i=2*k+1; i<length-1; i=2*i+1){    //i为初始化为节点k的左孩子,沿节点较大的子节点向下调整
                 if(i<length && array[i]<array[i+1]){  //取节点较大的子节点的下标
                     i++;   //如果节点的右孩子>左孩子,则取右孩子节点的下标
                 }
                 if(temp>=array[i]){  //根节点 >=左右子女中关键字较大者,调整结束
                     break;
                 }else{   //根节点 <左右子女中关键字较大者
                     array[k] = array[i];  //将左右子结点中较大值array[i]调整到双亲节点上
                     k = i; //【关键】修改k值,以便继续向下调整
                 }
             }
             array[k] = temp;  //被调整的结点的值放人最终位置
         }    
     //删除堆顶元素操作
         public int[] deleteMax(int[] array){
             //将堆的最后一个元素与堆顶元素交换,堆底元素值设为-99999
             array[0] = array[array.length-1];
             array[array.length-1] = -99999;
             //对此时的根节点进行向下调整
             adjustDownToUp(array, 0, array.length);
             return array;
         }
     //插入操作:向大根堆array中插入数据data
          public int[] insertData(int[] array, int data){
              array[array.length-1] = data; //将新节点放在堆的末端
              int k = array.length-1;  //需要调整的节点
              int parent = (k-1)/2;    //双亲节点
              while(parent >=0 && data>array[parent]){
                  array[k] = array[parent];  //双亲节点下调
                  k = parent;
                  if(parent != 0){
                     parent = (parent-1)/2;  //继续向上比较
                 }else{  //根节点已调整完毕,跳出循环
                     break;
                 }
             }
            array[k] = data;  //将插入的结点放到正确的位置
             return array;
         }
    

    本文并不是完全一篇原创文,希望能对你有所帮助.

  • 相关阅读:
    利用CMake生成动态或静态链接库工程
    pdfminer的TextConverter得到文件字符无空格解决方法
    从面向对象的设计模式看软件设计
    google python/c++ code style naming
    python入门之random模块
    python入门之time模块和datetime模块
    关于使用rancher部署k8s集群的一些小问题的解决
    centos虚拟机安装指定版本docker
    k8s的nfs存储外挂设置过程
    【Jenkins】执行yarn install报错:error An unexpected error occurred:"... ... :Unexpected end of JSON input"
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13285183.html
Copyright © 2011-2022 走看看