从partial_sort挖掘堆排序

   用过多次STL中的partial_sort算法,却全然不知其实现原理,也没跟进STL源码中去深究。某天在电话面试的时候被问到它的实现原理,没能答出来,实在惭愧。阅读partial_sort源代码以后,有种似曾相识的感觉,哦~~原来是堆排序。以前只在书本上了解过堆排序,没去认真了解和实现过,着实不知道它的妙处所在,如今灾难降临,给自己敲响警钟。

  堆排序:

  关键字序列k[1...n]当满足ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤ n/2 )这一条件时,称该序列为堆序列,将此序列看成是完全二叉树的话,则该二叉树满足这一条件:树中任一非叶结点的关键字不大于或不小于它的左右孩子的关键字。

  因此要实现堆排序应先解决两个问题: 1.创建满足条件的堆MakeHeap; 2.对堆进行排序HeapSort。

  奇怪,创建堆的时候不是根据条件已经排好序了吗?条件中仅仅说明非叶结点和左右子结点之间的关系,并没有说到左右子结点之间的关系,所以,还必须再排序。那要怎么排?画出二叉堆后很容易看出来,根部关键字肯定最大(或最小),所以,只需将其与序列末端的结点交换,交换以后,破坏了原有堆性质,必须重新创建新堆,当然,除去刚交换过后的“最值”结点(它不用再参与堆排序),如此反复,将会得到一个有序的序列。以下为创建小根堆和堆排序的代码:

void AjustHeap(int *arr, int len, int k)    //调整堆

      int th = 2*k+2;                    //定位序号为k结点的左右孩子
    for (; th < len; th = 2*th+2) //当结点的孩子也为非叶结点时,继续调整以该孩子为根部的小堆
  {
     if (arr[th] > arr[th - 1])
     {
          th--;
     }
     if (arr[k] > arr[th])
     {
        swap(arr[k], arr[th]);
     }
   }
   if (th == len && arr[k] > arr[th - 1])
   {
      swap(arr[k], arr[th - 1]);      //非叶结点只有一个孩子(必定在序列最后)的情况
   }
}

void MakeHeap(int *arr, int len)   //创建堆
{
   for (int i = len/2; i > 0;)            //从最后一个非叶结点开始
   {
      --i;
      AjustHeap(arr, len, i, arr[i]);
   }
}

void PopHeap0(int *arr, int len)   //将根部结点交换到最后
{
   swap(*arr, *(arr + len - 1));
}

void HeapSort(int *arr, int len)    //堆排序
{
   MakeHeap(arr, len);
   for (int i = len; i > 1; --i)
   {
      PopHeap0(arr, i);
      MakeHeap(arr, i - 1);
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值