堆排序

 

堆的定义

n个元素的序列H={k1, k2 , … kn} ,满足:

其中: i=1,2 , …, ën/2û

由堆的定义知,堆是一棵以k1为根的完全二叉树。若对该二叉树的结点进行编号(从上到下,从左到右),得到的序列就是将二叉树的结点以顺序结构存放,堆的结构正好和该序列结构完全一致。

 

2  堆的性质

①  堆是一棵采用顺序存储结构的完全二叉树, k1是根结点;

②  堆的根结点是关键字序列中的最小(或最大)值,分别称为小(或大)根堆;

③  从根结点到每一叶子结点路径上的元素组成的序列都是按元素值(或关键字值)非递减(或非递增)的;

④  堆中的任一子树也是堆。

利用堆顶记录的关键字值最小(或最大)的性质,从当前待排序的记录中依次选取关键字最小(或最大)的记录,就可以实现对数据记录的排序,这种排序方法称为堆排序。

 

3  堆排序思想

①  对一组待排序的记录,按堆的定义建立堆;

②  将堆顶记录和最后一个记录交换位置,则前n-1个记录是无序的,而最后一个记录是有序的;

③  堆顶记录被交换后,前n-1个记录不再是堆,需将前n-1个待排序记录重新组织成为一个堆,然后将堆顶记录和倒数第二个记录交换位置,即将整个序列中次小关键字值的记录调整(排除)出无序区;

④  重复上述步骤,直到全部记录排好序为止。

 结论:排序过程中,若采用小根堆,排序后得到的是非递减序列;若采用大根堆,排序后得到的是非递增序列。

 

堆排序的关键

①  如何由一个无序序列建成一个堆?

②  如何在输出堆顶元素之后,调整剩余元素,使之成为一个新的堆?

4  堆的调整——筛选

⑴ 堆的调整思想

   输出堆顶元素之后,以堆中最后一个元素替代之;然后将根结点值与左、右子树的根结点值进行比较,并与其中小者进行交换;重复上述操作,直到是叶子结点或其关键字值小于等于左、右子树的关键字的值,将得到新的堆。称这个从堆顶至叶子的调整过程为“筛选”,如图10-10所示。

注意:筛选过程中,根结点的左、右子树都是堆,因此,筛选是从根结点到某个叶子结点的一次调整过程。

 

⑵  堆调整算法实现

void Heap_adjust(Sqlist *H, int s, int m)

/*  H->R[s…m]中记录关键字除H->R[s].key均满足堆定义  */

/*  调整H->R[s]的位置使之成为小根堆  */

         int j=s, k=2*j ;     /*  计算H->R[j]的左孩子的位置  */

         H->R[0]=H->R[j] ;       /*  临时保存H->R[j]  */

         for (k=2*j; k<=m; k=2*k)

         { 

                   if ((k<m)&&(LT(H->R[k+1].key, H->R[k].key))

                        k++ ;      /*  选择左、右孩子中关键字的最小者  */

                   if  ( LT(H->R[k].key, H->R[0].key) )

               {  

                            H->R[j]=H->R[k] ;

                            j=k ;

                            k=2*j 

                   }

                   else  break ;

         }

         H->R[j]=H->R[0] ;

}

 

5  堆的建立

利用筛选算法,可以将任意无序的记录序列建成一个堆,设R[1],R[2], …,R[n]是待排序的记录序列。

将二叉树的每棵子树都筛选成为堆。只有根结点的树是堆。第⌊n/2⌋个结点之后的所有结点都没有子树,即以第ën/2û个结点之后的结点为根的子树都是堆。因此,以这些结点为左、右孩子的结点,其左、右子树都是堆,则进行一次筛选就可以成为堆。同理,只要将这些结点的直接父结点进行一次筛选就可以成为堆…。

只需从第ën/2û个记录到第1个记录依次进行筛选就可以建立堆。

可用下列语句实现:

for (j=n/2; j>=1; j--)

Heap_adjust(R, j , n) ;

 

6   堆排序算法实现

堆的根结点是关键字最小的记录,输出根结点后,是以序列的最后一个记录作为根结点,而原来堆的左、右子树都是堆,则进行一次筛选就可以成为堆。

void  Heap_Sort(Sqlist *H)

         int j ;

         for (j=H->length/2; j>0; j--)

                   Heap_adjust(H, j , H->length) ;   /*   初始建堆   */

         for (j=H->length/2; j>=1; j--)

         { 

                   H->R[0]=H->R[1] ;

                   H->R[1]=H->R[j] ;

                   H->R[j]=H->R[0] ;   /*   堆顶与最后一个交换   */

                   Heap_adjust(H, 1, j-1) ;

         }

}

 

堆排序的比较次数的数量级为: T(n)=O(n㏒2n);

而附加空间就是交换时所用的临时空间,故空间复杂度为: S(n)=O(1) 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值