posts - 34,comments - 2,trackbacks - 0
估计还要问问:什么是堆,什么是堆排序?堆与计算机分配内存的堆相同吗?
很多资料给出:堆的定义是
(1)、n个关键字序列(Kl,K2,…,Kn)称为(Heap),当且仅当该序列满足如下性质(简称为堆性质):
ki≤K2i且ki≤K2i+1 或  Ki≥K2i且ki≥K2i+1 (1≤i≤ n) //ki相当于二叉树的非叶结点,K2i则是左孩子,k2i+1是右孩子 

(2)若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:
  树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。

(3)、根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆,又称最小堆。根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆。

(4)、堆中任一子树亦是堆。
(5)、堆可以视为一棵完全的二叉树,完全二叉树的一个“优秀”的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用
数组来表示(普通的一般的二叉树通常用链表作为基本容器表示),每一个结点对应数组中的一个元素。

那么堆排序呢?
堆排序其实就是将一组无序的序列变成堆的过程、下面我们一起看看堆排序的算法。
2、堆排序
以最大堆为例,步骤为:
  ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
  ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
  ③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
  ……
  直到无序区只有一个元素为止。  
将一个无序的序列建成堆的过程实际上是一个反复筛选的过程。若将此序列看作是一棵完全二叉树,则最后一个非终端结点是[n/2](不大于n/2的整数),因此筛选过程只需从[n/2]开始。要建成一个大顶堆,即先选择一个值最大的元素并与序列中的最后一个元素交换,然后对序列前n-1元素进行筛选,从新调整为一个大顶堆,直到结束。 
算法描述如下: 
  
typedef   int[]   Elem;//采用顺序存储表示完全二叉树 

void   HeapAdjust(Elem   &e,int   s,int   m) 
{//e中s...m的元素除e[s]之外已经满足堆的定义(e[i] <=e[2*i]&&e[i] <=e[2*i+1] 
  //或e[i]> =e[2*i]&&e[i]> =e[2*i+1]),调整e[s]使的e[s...m]成为一个大顶堆。 
      selem=e[s]; 
      for(i=2*s;i <=m;i*=2)//沿着值较大的元素(结点)向下筛选 
      { 
            if(i <m   &&   e[i] <e[i+1])++i;//i为值较大的元素下标 
            if(selem> =e[i])break; 
            e[s]=e[i]; 
            s=i; 
        } 
      e[s]=selem; 
} 

void   HeapSort(Elem   &e) 
{//对顺序表排序 
    for(i=e.length/2;i> 0;--i) 
            HeapAdjust(e,i,e.length); 
    for(i=e.length;i> 1;--i) 
    { 
          temp=e[1];                     //将堆中的最后一个元素与第一个元素交换 
          e[1]=e[i]; 
          e[i]=temp; 
          HeapAdjust(H,1,i-1);//调整1..i-1的元素成为大顶堆 
      }     
}


/////////////////////////////////////////////////////////////
使用堆排序注意的问题:::
1、序列是从1开始的。,注意定义,R[1..n],故要空出R[0]。
2、堆排序算法分为两部分:建立大顶堆和排序。
3、排序的最坏时间复杂度为O(nlogn)。堆序的平均性能较接近于最坏性能。
4、由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
5、 堆排序是就地排序,辅助空间为O(1), 它是不稳定的排序方法。

问题:当序列空间为R[0,1....n];时,该怎么去使用堆排序呢?元素后移一位,这明显不是一个好方法。
posted on 2011-10-01 16:55 Yu_ 阅读(1083) 评论(0)  编辑 收藏 引用 所属分类: 数据结构

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理