您的位置:首页 > 其它

算法导论例程——堆排序(大根堆为例)

2016-02-04 23:12 281 查看
堆排序是具有原址性的排序,复杂度为o(nlgn)。

首先要建立一个“堆”的概念,堆 可以理解为二叉树的一种,是节点间有序关系的完全二叉树,即除了最后一层外节点没有缺失,所以可以用数组来表示。对于下标为i的节点,它的子树的左节点的下标为2*i,右节点为2*i+1,父树的节点下标为i/2(向下取整)。而在程序设计中,使用位运算来代替直接*2可以提高运行速度。而某些编译器中会把一些特定的乘法运算改写为位运算。

只把数组建立成堆是没有意义的,我们利用堆的性质,定义了两种特殊的堆,大根堆和小根堆。

大根堆,即任意一个节点都不小于它的两个子节点,这样递归的定义得到的结果之一,就是大根堆的根节点是所有节点中最大的。

小根堆的定义可以类比大根堆。

这里的堆排序以大根堆为例。

首先我们要建立一种方法,就是“大根堆化”(max_heapify)。对于给定的下标,我们计算出它的子树的左节点和右节点的下标,当下标不超过数组的有效长度length时,我们认为这个堆的扩展是有意义的,之后呢我们进行比较,首先比较左节点和给定节点的大小,并通过一个临时变量largest来记录较大节点的下标,之后再比较a[largest]和右节点的大小,同样的,用largest记录较大的下标。这样我们就得到了这三个节点中最大的那个,而当largest不等于给定的节点的下标时,我们交换这两个节点,以保证他们可以满足大根堆的性质。而接下来,被替换的新的子节点又面临同样的问题,即它的子树是否能构成大根堆,这样递归下去,知道无法产生有意义的子树,或是全部子树都满足大根堆的定义。

接下来看如何进行排序,根据上面的性质,我们知道,大根堆的根节点一定是所有节点中最大的,那么我们可以用数组的最末一位和根节点交换,然后缩小数组规模使最后一位不参与接下来的调整,之后再从a[0]建立一次大根堆,不断重复,直到数组被建堆的规模为2,就将原数组按升序重新排序了。

#include <stdio.h>
inline int LEFT(int i)
{
return 2 * i;                                              //左子树的根节点的下标
}
inline int RIGHT(int i)
{
return 2 * i + 1;                                          //右子树的根节点的下标
}

void heap_sort(int a[], int length);                            //堆排序函数
void build_max_heap(int a[], int length);                       //创建大根堆函数
void max_heapify(int a[], int start, int length);               //大根堆化函数

int main()
{
int a[1000] = { 0 }, n = 0, length = 0, i = 0;
printf("请输入要排序的数组规模:");
scanf("%d", &n);
length = n;
while (n--)
scanf("%d", &a[i++]);

heap_sort(a, length - 1);

i = 0;
while (length--)
printf("%d,", a[i++]);

return 0;
}

void heap_sort(int a[], int length)
{
int i = 0;
build_max_heap(a, length);

for (i = length; i > 0; i--)
{
a[i] += a[0];
a[0] = a[i] - a[0];
a[i] -= a[0];

max_heapify(a, 0, i - 1);
}
}

void build_max_heap(int a[], int length)
{
for (int i = length / 2; i >= 0; i--)
max_heapify(a, i, length);
}

void max_heapify(int a[], int start, int length)
{
int l = LEFT(start), r = RIGHT(start), largest;

if (l <= length && a[l] > a[start])
largest = l;
else
largest = start;

if (r <= length && a[r] > a[largest])
largest = r;

if (largest != start)
{
a[largest] += a[start];
a[start] = a[largest] - a[start];
a[largest] -= a[start];
max_heapify(a, largest, length);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: