zoukankan      html  css  js  c++  java
  • 堆排序

    堆排序:

    要知道堆排序,首先要了解一下二叉树的模型。

    下图就是一颗二叉树,具体的情况我后续会分享的。

    那么堆排序中有两种情况(看上图理解):

        大根堆:  就是说父节点要比左右孩子都要大。

        小根堆:  就是说父节点要比左右孩子都要小。

    那么要实现堆排序,必须要做两件事情:

       第一:构建大根堆。

               首先上图:

               

    首先这是一个无序的堆,那么我们怎样才能构建大根堆呢?

         第一步: 首先我们发现,这个堆中有2个父节点(2,,3);

         第二步: 比较2这个父节点的两个孩子(4,5),发现5大。

         第三步: 然后将较大的右孩子(5)跟父节点(2)进行交换,至此3的左孩子堆构建完毕,

                     如图:

                             

         第四步: 比较第二个父节点(3)下面的左右孩子(5,1),发现左孩子5大。

         第五步: 然后父节点(3)与左孩子(5)进行交换,注意,交换后,堆可能会遭到破坏,

                     必须按照以上的步骤一,步骤二,步骤三进行重新构造堆。

               

    最后构造的堆如下:

                     

       第二:输出大根堆。

                 至此,我们把大根堆构造出来了,那怎么输出呢?我们做大根堆的目的就是要找出最大值,

             那么我们将堆顶(5)与堆尾(2)进行交换,然后将(5)剔除根堆,由于堆顶现在是(2),

             所以破坏了根堆,必须重新构造,构造完之后又会出现最大值,再次交换和剔除,最后也就是我们

             要的效果了。

    堆的定义:n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质):

    ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n/2),当然,这是小根堆,大根堆则换成>=号。//k(i)相当于二叉树的非叶子结点,K(2i)则是左子节点,k(2i+1)是右子节点
     
          堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

    说明:它是不稳定的排序方法。(排序的稳定性是指如果在排序的序列中,存在前后相同的两个元素的话,排序前 和排序后他们的相对位置不发生变化)

     1 #include<iostream>
     2 #include <ctime>  //使用了time() 函数 
     3 #include <cstdlib>    //使用了srand()函数 
     4 
     5 const int N=3005;
     6 int a[N];
     7 using namespace std;
     8 //堆排序
     9 //整理节点time:O(lgn)
    10 
    11 void AdjustHeap(int *a,int parent,int length)
    12 {
    13      //temp保存当前父节点 
    14     int temp=a[parent];
    15     //得到左孩子(这可是二叉树的定义,大家看图也可知道)
    16     int child=2*parent;
    17     while(child<=length)
    18     {
    19         //如果parent有右孩子,则要判断左孩子是否小于右孩子
    20         if (child + 1 < length && a[child] < a[child + 1])   child++;//此方法用了点小技巧,大家认真思考一下 
    21         if(temp>=a[child])  break;    //父节点大于子节点,就不用了,建堆完成 
    22         //另一种情况则是小于
    23         a[parent]=a[child];  //大的子节点赋值给父节点 
    24         parent=child;     //子节点做为父节点 
    25         child=2*parent;   //步长增,进入下一节点 
    26     }
    27     a[parent]=temp;   //完成后,将temp赋值给此节点即可完成建堆 
    28 }
    29 
    30 //堆排序time:O(nlgn)
    31 void HeapSort(int*a,int n)
    32 {
    33   int i;
    34   for(i=n/2;i>=1;i--)     //从最后一个父节点一至到第一个 
    35   {
    36     AdjustHeap(a,i,n);     //对每个父节点进行一次建堆 
    37   }
    38   //最后输出堆元素
    39  for(int i=n;i>1;i--)
    40  {
    41      //堆顶与当前的第i个元素进行对调
    42      int temp=a[1];
    43      a[1]=a[i];
    44      a[i]=temp;
    45      //对调后,再对1...i-1的元素进行建堆,此时只需要从第1个元素开始到最底层即可
    46       AdjustHeap(a,1,i-1); 
    47  }
    48 }
    49 
    50 int main()
    51 {
    52     //随机产生3000个数存入数组a中 
    53     srand(int(time(0)));      //利用时间函数time(),产生每次不同的随机数种子
    54     for(int i=1;i<=3000;i++) a[i]=rand();  //随机产生3000个数存于数组a中 (从1开始) 
    55     clock_t start = clock();     // 计时开始
    56     HeapSort(a, 3000);                   //对数组a进行排序(从1开始) 
    57     clock_t end = clock();       //计时结束
    58     for(int i=1;i<=20;i++) cout<<a[i]<<' ';    //输出前20个数据(已从小到大排序) 
    59     cout<<endl<<"堆排排序耗时为:"<<end-start<<"ms"<<endl;     //输出排序所用的时间:结束时间-开始时间(单位为毫秒)
    60     return 0;
    61 }
  • 相关阅读:
    macbook 无声音解决方案
    webapck dev server代理请求 json截断问题
    百度卫星地图开启
    服务器 nginx配置 防止其他域名绑定自己的服务器
    记一次nginx php配置的心路历程
    遇到npm报错read ECONNRESET怎么办
    运行svn tortoiseSvn cleanup 命令失败的解决办法
    svn add 命令 递归目录下所有文件
    m4出现Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread, ungetc on your system, then report this to bug-gnulib."
    Ubuntu下安装GCC,mpc、mpfr、gmp
  • 原文地址:https://www.cnblogs.com/jjzzx/p/5072111.html
Copyright © 2011-2022 走看看