堆排序

今天算法课上,老师比较纤细的讲解了堆排序的相关始末,弥补了数据结构课上没有明白的情况,现总结如下。


引言:其实很多数据结构都是解决一些很现实的问题而被创建出来的。比如从最简单的一组数字开始说明;我们对于一串任意排列的数字,一般的操作有什么呢?无非就是

1.排序(排序之后可以很快的查到相应的数字,但数组插入数据是就涉及到相应的维护有序的工作,于是乎就会涉及很多的移动);

         对于这一点,我们可以采取一些策略优化针对插入时庞大的维护量,比如建立链表,抑或有序二叉树等;

2.查找比较特殊的值(比如说最大,最小值);

其实就基于第一点而言,如果提供了有序数组,一般能够比较快的给出最大最小值,这不必多说!

但是,如果仅仅只是为了快速查找最值,那我们可以对数据结构做一番大的优化,第一,我们不再需要完全有序的序列,因为我们只需要提供最值;第二,我们甚至不再需要什么很占空间的链表或者树来存储信息,我们在此引入“堆”的概念,我们仅仅需要一个数组空间,然后根据树的位置顺序进行建堆和修改即可;


这次我们“大根堆”为例(大根堆就是每一个父节点都要比他的儿子节点数值大;另外,儿子节点间的大小顺序任意):

那么,它的Insert和delete等操作都要基于一下的两个基本操作:

sift-up:

 
bool done=false;
if(i==1) 
   break;
while(!done || i>=1)
{
    if(A[i]>A[i/2])
    {
	temp=A[i];
	A[i]=A[i/2];
	A[i/2]=temp;
    }
   else
      done=true;
   i=i/2;
}

 

sift_down:

bool done=false;
if(2*i>n) 
   break;
while(!done || i<=n)
{
    if(A[i]<A[2*i])
    {
	int  temp=A[];
	A[i]=A[2*i];
	A[2*i]=temp;
    }
   else
      done=true;
   i=i*2;
}


”上浮“:完成了将不适合做儿子的节点进行上移,直到合适为止;

”下沉“:完成了将不适合做父亲的节点进行下移,直到合适为止;


那么现在,我们来看插入功能的实现。

根据堆的数据结构特点(完全二叉树和利用数组),我们先将数字加到数组末尾;将它进行sift-up操作;这样,他就可以到达合适的位置,并且保证整个队的性质。

n=n+1;
A[n]=x;
sift-up(A,n);

紧接着,我们来看看删除功能。

首先,去最后一个数值来覆盖现在要删除的数值;接着,对新移动的数值进行sift-up或sift-down操作,具体是情况而定。(那么,如果删除的是最顶端的---也就是最大值,那么显而易见,只需要对移动后的它做sift-down操作即可)

if(i==n)    
     return;//如果是尾结点,直接删除
x=A[i];  y=A[n];
n=n-1;A[i]=y;
if(A[i]>A[i/2] && i>1)  
    sift-up(A,i);
else  
    sift-down(A,i);


最后,关于建堆
1.如果从零开始一个一个添加,并对每一个进行sift-up操作即可建堆;
2.如果已经给定一个任意的数组,把它调整成“堆”只需要对非叶节点进行sift-down操作,目的就是自下而上的建堆,也就是说先保证每个小堆建成,随后一层层向上将堆建高,最总一定会建成一棵大的二叉树!

for(int i=n/2; i>=1; i--)
    sift-down(A,i);



基本的对操作就这么多,那么最后的最后,我们引出期待已久的 堆排序
基本思想是,每次将最大值和末位交换,并将新交换到首位的进行调整,即经过调整后,A[n] 的前n-1位重新成为一个大顶堆;

for(int i=n; i>=2; i--)
{
   temp=A[i];
   A[i]=A[1];
   A[1]=temp;

   sift-down(A,1);
}

这样,我们不需要额外的空间,并且以O(n*logn)的时间复杂度为代价,就可以生成一个生序排列的数组喽!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值