堆排序

来源:互联网 发布:洛奇英雄传mac 编辑:程序博客网 时间:2024/06/02 01:17

假设有序列:K1,K2,...Kn

1、如果满足:Ki>=K2i且Ki>=K2i+1,则称这个序列为大根堆。

2、如果满足:Ki<=K2i且Ki<=K2i+1,则称这个序列为小根堆。


大根堆排序的大致流程如下:



整个过程在数组中进行操作,交换堆顶元素和最后一个元素就是交换数组中的第一个元素与最后一个元素。

假设有数组a[0]a[1]a[2]…a[n-1](大根堆),交换后成为a[n-1]a[1]a[2]…a[0]。从而形成新序列a[n-1]a[1]a[2]…a[n-2],对这个新序列再进行调整、交换。

一共会产生n-1个新序列。

最外层循环:

for(j=n-1;j>0;j--){};

注:去掉的部分为有序元素,不参与后面的排序。实际上在排序过程中原数组的长度是不变的。

j=0:


j=1:


j=2:


...

j=8:


数组中的元素看成是完全二叉树。

大根堆调整: HeapAdjust(int low,int high)

假设有以下数据:


写成完全二叉树如下:



先将这个完全二叉树的局部(根节点、左子树、右子树)调整成大根堆:

锁定要排序的元素,会有2种情况:(i为对应数组的下标)


上面的完全二叉树属于第1种情况,

9个数,a[0]~a[8]

low=0,high=8.

i分别取:8,6,4,2

再假设共10个数,a[0]~a[9],此时属于第2种情况,

low=0,high=9

i分别取:9,8,6,4,2

怎么区分这两种情况?

if(i%2==0)//第一种情况

if(i%2==1)//第二种情况

调整成大根堆:

if(i%2==0)

{

for(i=high;i>=2;i-=2)

{

   if(a[(i-2)/2]<a[i-1])

 {

    temp=a[i-1];

    a[i-1]=a[(i-2)/2];

   a[(i-2)/2]=temp;

}

if(a[(i-2)/2])<a[i])

{

    temp=a[i];

    a[i]=a[(i-2)/2];

    a[(i-2)/2]=temp;

}

 

}

 

}       

if(i%2==1)

{

   if(a[(high-1)/2]<a[high])

   {

      temp=a[high];

      a[high]=a[(high-1)/2];

      a[(high-1)/2]=temp;

}

for(i=high-1;i>=2;i-=2)

{

   if(a[(i-2)/2]<a[i-1])

 {

    temp=a[i-1];

    a[i-1]=a[(i-2)/2];

    a[(i-2)/2]=temp;

}

if(a[(i-2)/2])<a[i])

{

    temp=a[i];

    a[i]=a[(i-2)/2];

    a[(i-2)/2]=temp;

}

}

}

交换大根堆中的堆顶元素和最后一个元素:

temp=a[0];

a[0]=a[j];

a[j]=temp;

最后套上最外层循环。
原创粉丝点击