您的位置:首页 > 编程语言 > C语言/C++

堆排序

2015-03-20 22:25 309 查看
堆排序利用了大根堆的两个特点:

1.      堆顶元素是最大元素;
2.      后一次堆调整可以在前一次的基础上进行;
堆排序利用了数组的一个特点:
1.      快速定位指定索引的元素;
使用了以上的特点使得对无序数组进行排序变得简单而高效。

用大根堆排序的基本思想

1.      先将初始文件R[0..n-1]建成一个大根堆,此堆为初始的无序区
2.      再将关键字最大的记录R[0](即堆顶)和无序区的最后一个记录R[n-1]交换,由此得到新的无序区R[0..n-2]和有序区R[n-1],且满足R[0..n-2].keys≤R[n-1].key
3.      由于交换后新的根R[0]可能违反堆性质,故应将当前无序区R[0..n-2]调整为堆。然后再次将R[0..n-2]中关键字最大的记录R[0]和该区间的最后一个记录R[n-2]交换,由此得到新的无序区R[0..n-3]和有序区R[n-2..n-1],且仍满足关系R[1..n-3].keys≤R[n-2..n-1].keys,同样要将R[0..n-3]调整为堆。

大根堆排序算法的基本操作:

1.      建堆,建堆是不断调整堆的过程,从len/2-1处开始调整,一直到根结点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2-1到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2)其中h表示结点的深度,len/2表示结点的个数,这是一个求和的过程,结果是线性的O(n)。
2.      调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较结点i和它的孩子结点left(i),right(i),选出三者最大者,如果最大值不是结点i而是它的一个孩子结点,那边交互结点i和该结点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调整的。
3.      堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根结点取出(一般是与最后一个结点进行交换),将前面len-1个结点继续进行堆调整的过程,然后再将根结点取出,这样一直到所有结点都取出。堆排序过程的时间复杂度是O(nlgn)。因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,所以堆排序的时间复杂度是O(nlgn)。由于建堆只调用了一次,当n很大,即元素个数较多时,建堆过程的时间消耗可以忽略不计。如果n值比较小,则建堆过程的时间消耗不能忽略。

具体的代码

 #include <stdio.h>
#define N 10
void heap_build(int array[], int length);
void heap_adjust(int array[], int i, int length);
void heap_sort(int array[], int length);
int main(void)
{
int buffer
= {1,2,3,4,5,6,7,8,9,0};
int i;

/*build up heap*/
heap_build(buffer, N);
for(i = 0; i < N; i++)
{
printf("%3d", buffer[i]);
}
printf("\nbuild heap successfully!\n");

/*heap sort*/
heap_sort(buffer,N);
for(i = 0; i< N; i++)
{
printf("%3d", buffer[i]);
}
printf("\nheap sort successfully!\n");
}
void heap_build(int array[], int length)
{
int i;
/*调整第一个非叶子结点至根结点*/
for (i = length / 2 - 1; i >= 0; i--)
{
heap_adjust(array, i, length);
}
}
void heap_adjust(int array[], int i, int length)
{
int lchild, rchild, max;
int temp;
while(i < length -1)
{
lchild = 2*i + 1;
rchild = 2*i + 2;
max = i;
if (lchild < length)
{
if (array[max] < array[lchild])
{
max = lchild;
}
}
else /*该结点不存在叶子结点,即该结点本身就是叶子结点*/
{
break;
}
if (rchild < length)
{
if (array[max] < array[rchild])
{
max = rchild;
}
}
if (max != i) /*该结点小于其子结点*/
{
/*交换,使该结点下移一层*/
temp = array[i];
array[i] = array[max];
array[max] = temp;
/*继续调整子结点,直至满足大根堆条件*/
i = max;
}
else /*该结点满足大根堆条件,不需调整*/
{
break;
}
}
}
void heap_sort(int array[], int length)
{
int i;
int temp;
for (i = length - 1; i > 0; i--)
{
/*交换根结点和最后一个结点*/
temp = array[i];
array[i] = array[0];
array[0] = temp;
/*在剩余无序区域中,继续调整根结点使之成为大根堆*/
heap_adjust(array, 0, i);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息