数据结构-堆排序

堆排序

       堆排序是利用堆的性质进行的一种选择排序。下面先讨论一下堆。

1.堆

  堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

  Key[i]<=key[2i]&&Key[i]<=key[2i+1]或者Key[i]>=Key[2i]&&key>=key[2i+1]

  即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。

  堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i]&&key>=key[2i+1]称为大顶堆,满足 Key[i]<=key[2i]&&Key[i]<=key[2i+1]称为小顶堆。由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

2.堆排序的思想

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

       其基本思想为(大顶堆):

       1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;

       2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n]; 

       3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

操作过程如下:

       1)初始化堆:将R[1..n]构造为堆;

       2)将当前无序区的堆顶元素R[1]同该区间的最后一个记录交换,然后将新的无序区调整为新的堆。

       因此对于堆排序,最重要的两个操作就是构造初始堆和调整堆,其实构造初始堆事实上也是调整堆的过程,只不过构造初始堆是对所有的非叶节点都进行调整。

    

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

       堆排序其实也是一种选择排序,是一种树形选择排序。只不过直接选择排序中,为了从R[1...n]中选择最大记录,需比较n-1次,然后从R[1...n-2]中选择最大记录需比较n-2次。事实上这n-2次比较中有很多已经在前面的n-1次比较中已经做过,而树形选择排序恰好利用树形的特点保存了部分前面的比较结果,因此可以减少比较次数。对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为nlogn。堆排序仅需要一个辅助空间,因此堆排序的空间复杂度是O(1),堆排序为不稳定排序。

代码:

 

#include<stdio.h>
int a[100];
int count=0;
void Init()
{
 int i;
 count=0;
 i=1;
 int value;
 printf("Please input an array end by -1:\n");
 while(1)
 {
  scanf("%d",&value);
  if(value==-1)
  break;
  else
  a[i++]=value;
  count++;
 }
}
void Output(int a[], int len, int i)
{
 int k=1;
 if(i==0)
 printf("The initial array is:\n");
 else
 printf("第 %d 趟排序结果为:\n",i);
 for(k=1;k<=len;k++)
 {
  printf("%4d",a[k]);
 }
 
  printf("\n");
}
void sift(int a[], int k, int len)//adjust the array to be a big root heap
{
    int i;
    int cur;
    cur=a[k];//Save the root information
    for(i=2*k; i<=len; i*=2)
    {
     if(i<len&&a[i]<a[i+1])
     i=i+1;
     if(cur>=a[i])
     break;
     else
     {
      a[k]=a[i];
      k=i;
     }
    }
    a[k]=cur;
}
void HeapSort(int a[], int len)
{
 int n, i;
 int temp;
 for(i=len/2; i>=1; i--)
 {
  sift(a, i, len);
 }
 n=len;
 for(i=n; i>=2; i--)
 {
  temp=a[1];
  a[1]=a[i];
  a[i]=temp;
  Output(a, len, n-i+1);
  sift(a, 1, i-1);
 }

}
int main()
{
 Init();
 Output(a, count, 0);
 HeapSort(a, count);
 
 return 0;
 
}
/*
Please input an array end by -1:
58 69 48 14 25 88 95 68 25 14 78 12 -1
The initial array is:
  58  69  48  14  25  88  95  68  25  14  78  12
第 1 趟排序结果为:
  12  78  88  68  69  58  48  14  25  14  25  95
第 2 趟排序结果为:
  25  78  58  68  69  12  48  14  25  14  88  95
第 3 趟排序结果为:
  14  69  58  68  25  12  48  14  25  78  88  95
第 4 趟排序结果为:
  14  68  58  25  25  12  48  14  69  78  88  95
第 5 趟排序结果为:
  14  25  58  14  25  12  48  68  69  78  88  95
第 6 趟排序结果为:
  14  25  48  14  25  12  58  68  69  78  88  95
第 7 趟排序结果为:
  12  25  14  14  25  48  58  68  69  78  88  95
第 8 趟排序结果为:
  12  25  14  14  25  48  58  68  69  78  88  95
第 9 趟排序结果为:
  12  14  14  25  25  48  58  68  69  78  88  95
第 10 趟排序结果为:
  14  12  14  25  25  48  58  68  69  78  88  95
第 11 趟排序结果为:
  12  14  14  25  25  48  58  68  69  78  88  95
Press any key to continue...
*/

 

posted @ 2013-03-24 10:58  蓝色L火焰  阅读(154)  评论(0编辑  收藏  举报