0. 堆排序包括两个部分 (只讨论由小到大排序这种情况)
a. 建堆 --> 建
立一个大顶,从第一个非叶结点开始由下到上调整堆
b. 堆排序
因为是大顶堆,max=arr[0],所以将arr[0] 与 arr[end]交换,然后[0-end-1]重新生成一个大顶堆
现在max=arr[0],再
将arr[0] 与 arr[end-1]交换,然后[0-end-2]重新生成一个大顶堆
以此类推
直至堆中只剩一个元素,堆排序过程结束
1.1 建堆的过程
对每一个非叶结点
建立一个大顶,从第一个非叶结点开始由下到上调整堆
1.2建堆的过程
-
#include <stdio.h>
-
#include <stdlib.h>
-
#define dbmsg(fmt, args ...) printf("%s:%s[%d]: "fmt"\n", __FILE__,__FUNCTION__, __LINE__,##args)
-
#define SWAP(x,y) (x=(x)+(y),y=(x)-(y),x=(x)-(y))
-
#define SWAP2(x,y) \
-
do{ if((x)<(y)) \
-
SWAP((x),(y));} \
-
while(0)
-
#define POW(x) (1<<(x))
-
#define L(x) (2*(x)+1) //left child
-
#define R(x) (2*(x)+2) //right child
-
int dump_array(int* arr, int len)
-
{
-
int i;
-
for(i=0; i<len; i++)
-
{
-
printf("%d ", arr[i]);
-
}
-
printf("\n");
-
return 0;
-
}
-
-
int is_sum_pow2(int n)
-
{
-
int t = n+1;
-
return n&t;
-
}
-
-
int get_level(int num)
-
{
-
int ret;
-
__asm__ volatile("movl %1,%%ecx\n"
-
"xor %%eax, %%eax \n"
-
"bsr %%ecx, %%eax \n"
-
"movl %%eax, %0 \n":"=r"(ret):"r"(num):);
-
return ret;
-
}
-
-
int dump_tree(int* arr, int len)
-
{
-
int i,j;
-
int level = get_level(len)+1;
-
int first = 1;
-
printf("<------------------\n");
-
for(i=0; i<len; i++)
-
{
-
if(first)
-
{
-
for(j=0; j<POW(level-1)-1; j++)
-
printf(" ");
-
first = 0;
-
}else {
-
for(j=0; j<POW(level)-1; j++)
-
printf(" ");
-
}
-
printf("%2d", arr[i]);
-
if( is_sum_pow2(i+1) == 0)
-
{
-
printf("\n");
-
level--;
-
first = 1;
-
}
-
}
-
printf("\n");
-
-
printf("------------------>\n");
-
return 0;
-
}
-
-
int heap_adjust(int* arr,int s, int len)
-
{
-
int i = s;
-
int temp;
-
int max;
-
while(i < (len-1)) //长度是len,但数组下标是[0-len-1]
-
{
-
if(L(i) > len-1) //如果左结点的下标己超过了数组的总长度,说明左结点不存在
-
break; //堆是一棵完全二叉树,左结点不存在说明这个是叶结点
-
if( (R(i)<(len-1)) && (arr[L(i)] < arr[R(i)])) //判断右结点是否存在,存在且大于左结点
-
max = R(i); //说明子结点中右结点的值大
-
else
-
max = L(i);
-
//到这儿己经找出最大的子结点的索引,然后parent与child相比较
-
if(arr[i] < arr[max]) //若p < c,则需要交换并调整
-
{
-
SWAP(arr[i], arr[max]); //交换p与c的位置
-
//arr[i] = arr[max];
-
}else {
-
break; //p > c,说明这一支都不需要调整,直接break
-
}
-
i = max; //然后在下一次循环中进行调整
-
dump_tree(arr, len);
-
}
-
//dump_tree(arr, len);
-
return 0;
-
}
-
-
int heap_sort(int* arr, int len)
-
{
-
int i;
-
//1. build heap
-
for(i=len/2-1; i>=0; i--) //第一个非叶结点的位置是len/2-1
-
{
-
printf("%d=%d\n", i, arr[i]);
-
heap_adjust(arr, i, len);
-
}
-
dump_tree(arr, len);
-
printf("next heap sort ----\n");
-
#if 0
-
//heap sort
-
for(i=len-1; i>0; i--)
-
{
-
SWAP(arr[0], arr[i]);
-
heap_adjust(arr, 0, i-1);
-
printf("%d=%d\n", i, arr[i]);
-
dump_tree(arr, len);
-
}
-
#endif
-
}
-
-
int main ( int argc, char *argv[] )
-
{
-
//int arr[] = {49, 38, 65, 97, 76, 13, 27, 49};
-
int arr[] = {49, 38, 65, 97, 76, 13, 27, 49, 55, 4};
-
int len = sizeof(arr)/sizeof(int);
-
dbmsg("array len=%d", len);
-
dump_tree(arr, len);
-
heap_sort(arr, len);
-
printf("after heap sort\n");
-
dump_tree(arr, len);
-
dump_array(arr, len);
-
return EXIT_SUCCESS;
-
}
1.3 执行结果如下
-
heap.c:main[125]: array len=10
<------------------
49
38 65
97 76 13 27
49 55 4
------------------>
4=76 -->76 4 不用调整
3=97 -->97 49 55 不用调整
2=65 -->65 13 27 不用调整
1=38 -->38 97 76 要调整
<------------------
49
97 65 -->38 97 76中97最大,将97与38交换,再调整38这一支
38 76 13 27
49 55 4
------------------>
<------------------
49
97 65
55 76 13 27 -->38 49 55中55最大,将55与38交换,38是叶结点了,调整结束
49 38 4
------------------>
0=49
<------------------
97 -->49 97 65中97最大,将97与49交换,再调整49这一支
49 65
55 76 13 27
49 38 4
------------------>
<------------------
97
76 65
55 49 13 27 -->49 55 76中76最大,将76与49交换,再调整49这一支
49 38 4
------------------>
<------------------
97
76 65
55 49 13 27 -->49 4中49最大,不用调整,调整结束
49 38 4
------------------>
next heap sort ----
after HeapSort
<------------------
97
76 65
55 49 13 27
49 38 4
------------------>
97 76 65 55 49 13 27 49 38 4
2.1 堆排序的过程
上一步己经建成一个大顶堆了,堆顶元素就是要排序数据的最大值
把最大值交换到数组的结尾,然后把剩下的数据再排成一个大顶堆,这样就找出了次大值
以此类推
虽然中间过程一直是大顶堆,最后输出总的数组时却是一个小顶堆,这样就完成了排序。
2.2 堆排序
-
#include <stdio.h>
-
#include <stdlib.h>
-
#define dbmsg(fmt, args ...) printf("%s:%s[%d]: "fmt"\n", __FILE__,__FUNCTION__, __LINE__,##args)
-
#define SWAP(x,y) (x=(x)+(y),y=(x)-(y),x=(x)-(y))
-
#define SWAP2(x,y) \
-
do{ if((x)<(y)) \
-
SWAP((x),(y));} \
-
while(0)
-
#define POW(x) (1<<(x))
-
#define L(x) (2*(x)+1) //left child
-
#define R(x) (2*(x)+2) //right child
-
int dump_array(int* arr, int len)
-
{
-
int i;
-
for(i=0; i<len; i++)
-
{
-
printf("%d ", arr[i]);
-
}
-
printf("\n");
-
return 0;
-
}
-
-
int is_sum_pow2(int n)
-
{
-
int t = n+1;
-
return n&t;
-
}
-
-
int get_level(int num)
-
{
-
int ret;
-
__asm__ volatile("movl %1,%%ecx\n"
-
"xor %%eax, %%eax \n"
-
"bsr %%ecx, %%eax \n"
-
"movl %%eax, %0 \n":"=r"(ret):"r"(num):);
-
return ret;
-
}
-
-
int dump_tree(int* arr, int len)
-
{
-
int i,j;
-
int level = get_level(len)+1;
-
int first = 1;
-
printf("<------------------\n");
-
for(i=0; i<len; i++)
-
{
-
if(first)
-
{
-
for(j=0; j<POW(level-1)-1; j++)
-
printf(" ");
-
first = 0;
-
}else {
-
for(j=0; j<POW(level)-1; j++)
-
printf(" ");
-
}
-
printf("%2d", arr[i]);
-
if( is_sum_pow2(i+1) == 0)
-
{
-
printf("\n");
-
level--;
-
first = 1;
-
}
-
}
-
printf("\n");
-
-
printf("------------------>\n");
-
return 0;
-
}
-
-
int heap_adjust(int* arr,int s, int len)
-
{
-
int i = s;
-
int temp;
-
int max;
-
while(i < (len-1))
-
{
-
if(L(i) > len-1)
-
break;
-
if( (R(i)<(len-1)) && (arr[L(i)] < arr[R(i)]))
-
max = R(i);
-
else
-
max = L(i);
-
if(arr[i] < arr[max])
-
{
-
SWAP(arr[i], arr[max]);
-
//arr[i] = arr[max];
-
}else {
-
break;
-
}
-
i = max;
-
//dump_tree(arr, len);
-
}
-
//dump_tree(arr, len);
-
return 0;
-
}
-
-
int heap_sort(int* arr, int len)
-
{
-
int i;
-
//1. build heap
-
for(i=len/2-1; i>=0; i--)
-
{
-
printf("%d=%d\n", i, arr[i]);
-
heap_adjust(arr, i, len);
-
}
-
printf("build heap over");
-
dump_tree(arr, len);
-
printf("next heap sort ----\n");
-
#if 1
-
//heap sort
-
for(i=len-1; i>0; i--) //从最后一个结点开始调整
-
{
-
SWAP(arr[0], arr[i]); //0与end交换
-
heap_adjust(arr, 0, i-1); //再调整成一个大顶堆
-
printf("%d=%d", i, arr[i]);
-
dump_tree(arr, len);
-
}
-
#endif
-
}
-
-
int main ( int argc, char *argv[] )
-
{
-
//int arr[] = {49, 38, 65, 97, 76, 13, 27, 49};
-
int arr[] = {49, 38, 65, 97, 76, 13, 27, 49, 55, 4};
-
int len = sizeof(arr)/sizeof(int);
-
printf("array len=%d, before sort", len);
-
dump_tree(arr, len);
-
heap_sort(arr, len);
-
printf("after heap sort");
-
dump_tree(arr, len); //最终结是是一个小顶堆
-
dump_array(arr, len);
-
return EXIT_SUCCESS;
-
}
3.3 执行结果如下:
-
array len=10, before sort<------------------
49
38 65
97 76 13 27
49 55 4
------------------>
4=76
3=97
2=65
1=38
0=49
build heap over<------------------ //建了一个大顶堆
97
76 65
55 49 13 27
49 38 4
------------------>
next heap sort ----
9=97<------------------ //将堆顶的97与最后的4交换,然后重新建大顶堆
76
55 65
49 49 13 27
4 38 97
------------------>
8=76<------------------ //将堆顶的76与倒数第二的38交换,然后重新建大顶堆
65
55 38
49 49 13 27
4 76 97
------------------>
7=65<------------------
55
49 38
4 49 13 27
65 76 97
------------------>
6=55<------------------
49
27 38
4 49 13 55
65 76 97
------------------>
5=49<------------------
38
27 13
4 49 49 55
65 76 97
------------------>
4=38<------------------
49
27 13
4 38 49 55
65 76 97
------------------>
3=49<------------------
27
4 13
49 38 49 55
65 76 97
------------------>
2=27<------------------
13
4 27
49 38 49 55
65 76 97
------------------>
1=13<------------------
4
13 27
49 38 49 55
65 76 97
------------------>
after heap sort<------------------
4
13 27
49 38 49 55
65 76 97
------------------>
4 13 27 49 38 49 55 65 76 97
-
3.4 注意
a. 如果在堆排序过程中有如下数据
49
65 76
49 65 76中最大的数是76,只需要将76与49交换即可,然后再调整49这一支的数据,65这一支不动即可
76
65 49
而只需要将76与49交换即可,不需要再将65与49交换.
76
49 65
3.5 代码
6heap.rar (下载后改名为heap.tar.gz)
阅读(983) | 评论(0) | 转发(0) |