排序方法之堆排序

11 篇文章 0 订阅
9 篇文章 0 订阅
堆排序的实现
(—)创建初始堆
(二)堆排序

在创建初始堆之前首先要了解一些关于堆的概念,还需要了解一些关于平衡二叉树的内容
 (1)堆的节点数 =n/2; 并且是只舍不入;
 (2)最后一个堆结点=(n/2)-1;
  (3)对于任意结点a[x],可以找到它子结点上的内容a[2x+1]和a[2x+2]

(——)创建一个堆

实现原理:
它考察堆的各个结点并且使之成为一个堆。这意味着各个结点的值无论何时小于它的子结点的值,都要对此节点与最大的子节点进行交换。对于每个结点,要检查是否应该改变,并且递归检查引起变化的子节点。

此代码重新排列了数组data内的内容,使各个结点的值都大
于其子结点的值,有效的创建了一个堆
 int i,j,j2,k;
   int tmp;
//外循环  :考虑所有的结点,从最后一个开始,直到根部
   for(k =(n>>1)-1;k>=0;k--)
      {
          //评价至该结点的k个点
           // k子女上的j2+1 与j2+2 结点
        tmp =data[k];
        //内循环:对于每个变化的结点,循环检查引起变
化的子节点
      for( j=k;(j<<1)<=n-2;j=i)
         {
                //查找节点k的最大子女
             j2 = j<<1;
             if(j2+2>n-1)//只有一个子女
               i=j2+1;
             else
                 { //有两个子女
                if(data[j2+1]<data[j2+2])
                      i=j2+2;
                else
                  i=j2+1;
                 }
                 //此时,i指向具有最大值的子女
              if(tmp<data[i])
               data[j]= data[i];
              else
                   break;
         }
        data[j]= tmp;
     }


(二)堆排序

实现原理:
 取堆的的根节点,也就是数组中最大的数,把它与数组中的最后一个元素交换。这个元素是最后一个结点最后一个树叶的子女。此时,前根元素恰好位于它应在的位置。但是要对新堆进行判断。方法同创建堆中的内循环相同。当新堆的重新判断完成后,再一次得到根元素,且把它与最后一个结点的最后一个页结点交换。

for(k=n-1;k>0;k--)
     {
       //至数组后部(已排序)的k个结点
       //根部与后部的元素交换
       tmp = data[k];
       data[k] =data[0];
         //再把数组压入堆中
       for(j=0;(j<<1) <= k-2;j=i)
           {
            j2 =j<<1;
            if( j2+2 > k-1 )
                i=j2+1;
            else
                {
               if(data[j2+1]<data[j2+2])
                     i=j2+2;
               else
                     i=j2+1;
                }
               
              if(tmp<data[i])
                   data[j]=data[i];
              else
                   break;              
           }


           data[j]=tmp;
     }
    for(j=0;j<n;j++)
       cout<<data[j];
  }

下面是堆排序的完整实现的代码示例。
#include<iostream>
using namespace std;
  void  heapsort(int *data,int  n )
  {
   int i,j,j2,k;
   int tmp;
//外循环  :考虑所有的结点,从最后一个开始,直到根部
   for(k =(n>>1)-1;k>=0;k--)
      {
          //评价至该结点的k个点
           // k子女上的j2+1 与j2+2 结点
        tmp =data[k];
        //内循环:对于每个变化的结点,循环检查引起变


化的子节点
      for( j=k;(j<<1)<=n-2;j=i)
         {
                //查找节点k的最大子女
             j2 = j<<1;
             if(j2+2>n-1)//只有一个子女
               i=j2+1;
             else
                 { //有两个子女
                if(data[j2+1]<data[j2+2])
                      i=j2+2;
                else
                  i=j2+1;
                 }
                 //此时,i指向具有最大值的子女
              if(tmp<data[i])
               data[j]= data[i];
              else
                   break;
         }
        data[j]= tmp;
     }
   


   for(k=n-1;k>0;k--)
     {
       //至数组后部(已排序)的k个结点
       //根部与后部的元素交换
       tmp = data[k];
       data[k] =data[0];
         //再把数组压入堆中
       for(j=0;(j<<1) <= k-2;j=i)
           {
            j2 =j<<1;
            if( j2+2 > k-1 )
                i=j2+1;
            else
                {
               if(data[j2+1]<data[j2+2])
                     i=j2+2;
               else
                     i=j2+1;
                }
               
              if(tmp<data[i])
                   data[j]=data[i];
              else
                   break;              
           }


           data[j]=tmp;
     }
    for(j=0;j<n;j++)
       cout<<data[j];
  }
 int main()

    int data[10]={9,6,3,8,5,2,7,4,1,0};
     heapsort(data,10); 
  return 0;
}
(三)
堆排序的优缺点
其复杂度为O(nlog2n),也适合较小量的数据
优点:
(1)平均情形和最坏情形时效率都很高。
 (2)运行时占用内存较少
缺点:
(1)算法不稳定
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值