堆排序(源码C)

   思路:

              堆排序主要分为俩个部分,一个是构建堆(主要的,根节点下的俩个子节点大小差距不一定,其子节点不一定按顺序排),另外一个是调整堆。

       

               构建堆(第一个for循环,自下而上)之后,初步的顺序出来了,堆顶便是最大的值,我们将他定为老大,俩个子节点为老二,俩个老二分别代表俩个分支,他们分别是俩个分支中的最强者(一人之下万人之上的老二之一)。但是这俩个左右分支实力不得而知,可能左节点下一个堂口的小弟便强于右节点的老二。不过可以确定的是,真正的第二强者在他们俩个之间。就在目前这个时期,我们是处于第一个FOR循环之中。

              到了第二个FOR循环,我们要将老大(top)放入名人堂中,他下岗,我们的第二强者上岗成为新的老大。不过在此之前,我们只有一个数组,那么我们要将小弟们(tail堆尾,也就是数组的尾部)的地方腾出来【swap(0,j)】,将小弟(tail)放入老大的位置而后,让各个分支、堂口去检验(也就是慢慢被刷回去,回到解放前 = =!!,adjustHeap(0,j)这个过程是自上而下的)。那么,俩个分支的老大会有一个成为新的top,他所在分支的俩个老三(堂主)会有一个成为新的分支老大,以此类推(可怜的小弟......)。然后老大不断进入”名人堂“,小弟渐渐没有,帮派灭亡,排序完成。

             过程中注意几个循环体的参数。


              构建堆

                           从length/2-1开始调整length/2-1次方能构建大顶堆。因为length/2-1开始才有叶子结点(从下至上,从右至左调整结构 )。


          调整:adjustHeap(i,length) ——调整i(有叶子节点的节点)及其子节点的叶子节点(for(k=i*2+1;k<length;k=k*2+1) ),将其调整为父节点最大,其次左节点,右节点,(层次排序)。


             便于理解构建堆的图解:https://www.cnblogs.com/chengxiao/p/6129630.html             

             便于理解调整的图解:https://www.cnblogs.com/MOBIN/p/5374217.html。看了好几个博客,这俩个各有所长。

            构建堆与调整堆:    最初的多次调整构建堆,后面微调,原本调好的顺序(分支)还记录在堆结构里面,避免重复换位这也是堆排序,堆结构的意义所在。   平均时间复杂度:O (nlgn)


#include <stdio.h>

int static arr[] = {9,8,11,6,5,4,3,2,1};

void sort(){
      //构建大堆顶
      int length = sizeof(arr)/sizeof(int);
      int i,j;
      for(i=length/2-1;i>=0;i--)   //length/2-1开始才有子节点
      {
          //从第一个非叶子节点从下至上,从右至左调整结构,分支大小差距不知   
          adjustHeap(i,length);     //构建大顶堆
      }
      //2、调整堆结构和交换堆顶元素与末尾元素
      for(j=length-1;j>0;j--)
      {
          swap(0,j);    //将堆顶元素与末尾元素交换,将堆顶放到堆尾,然后重新构建大顶堆(原有基础上),堆尾就不用管了,所以这里是j--,表示一个top进入名人堂,少了一个小弟
          adjustHeap(0,j);  // 重新对堆进行调整,调整时,从堆顶往下调(构建大顶堆)所以此时i是0,堆顶下面的俩个分支是已经调好的,然后如果新的堆顶很小那他会一直被换到底部(可能进入另外一个分支当老大),保证最强者是俩个分支的老大。
      }

}

void adjustHeap(int i,int length) 
{
    int temp = arr[i];
    int k;
    /**一个for循环比较一个父节点和他的子节点们(俩个)**/
    for(k=i*2+1;k<length;k=k*2+1)    // k=i*2+1即为i的左叶子节点,k=k*2+1,该节点的子节点如果有叶子节点的话,继续比较,直至者一支/堂/...比较完
    {
        if(k+1<length && arr[k]<arr[k+1])   // 保证左大于右
        {
            k++;
        }
        if(arr[k]>temp)             // 如果子节点大于父节点,讲子节点赋值给父节点(不用进行交换【其实是交换第一部分】)
        {
            arr[i] = arr[k];
            i=k;
        }else{
          break;
        }
    }
    arr[i] = temp;  //讲temp值放到最终的位置【其实就是交换分俩部分,这是最后一部分】
}

void swap(int a,int b)
{
    int t;
    t = arr[a];
    arr[a] = arr[b];
    arr[b] = t;
}

int main()
{
    int i;
    sort();
    int length = sizeof(arr)/sizeof(int);
    for(i=0;i<length;i++)
    {
         printf("%d",arr[i]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37334150/article/details/79512426
今日推荐