堆排序

1、什么是堆?

      堆实际上是一棵完全二叉树,任何一个父节点都大于其左右两个子树(如果有子树的话)。完全二叉树的性质还包括了父节点与直接子节点的关系。Index(父)=[Index(子)-1]/2

最大堆:Key[i]>=Key[2i+1]&&key>=key[2i+2];堆顶关键字最大。


 

最小堆:Key[i]<=key[2i+1]&&Key[i]<=key[2i+2];对顶关键字最小。


 

 2.堆排序的思想

      利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。

    下面举例说明,用最大堆为例:

    给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。

    首先根据该数组元素构建一个完全二叉树,得到(旁边的数字为下标)


 

 然后需要构造初始堆,则从最后一个非叶节点(下标为2的8不用调整,满足最大堆的条件)开始调整,调整过程如下:


 

20和16交换后导致16不满足堆的性质,因此需继续调整,这也是堆的下调过程。


 

这样就得到了初始堆

即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换,交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要继续对被交换的孩子节点进行调整。有了初始堆之后就可以进行排序了。

排序过程:

1、        取出堆顶元素

2、       堆顶 用最后一位元素代替堆,堆的大小减一,然后下调堆顶元素。

3、        重复1、2。

C++:

#include<iostream>
 
namespace mySort
{
//下调函数,请仔细阅读,即可理解。
      void AdjustDown(int *data, int r, int j)
      {
           int child = 2 * r + 1;
           int temp = data[r];
           while (child <= j)
           {
                 if ((child<j) &&(data[child + 1]>data[child]))
                      child++;
                 if (temp >= data[child])
                      break;
                 data[(child - 1) / 2] =data[child];
                 child = child * 2 + 1;
           }
           data[(child - 1) / 2] = temp;
      }
      void heapSort(int * data, int n)
      {
           for (int i = (n - 2) / 2; i >= 0;--i)
                 mySort:: AdjustDown(data,i,  n-1);
           for (int i = n - 1; i > 0; --i)
           {
                 std::swap(data[0], data[i]);
                 mySort::AdjustDown(data, 0,i-1);
           }
      }
};
 
int main()
{
      int a[] = { 3,    1 };
      int len = sizeof(a) / sizeof(int);
      mySort::heapSort(a,len);
      return 0;
}


总结:

从上述过程可知,是一种树形选择排序。对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为n*(log(n))。堆排序为不稳定排序,不适合记录较少的排序。


posted @ 2014-08-21 20:37  旧客图新  阅读(226)  评论(0)    收藏  举报