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建堆的过程
1.3 执行结果如下
2.1 堆排序的过程
上一步己经建成一个大顶堆了,堆顶元素就是要排序数据的最大值
把最大值交换到数组的结尾,然后把剩下的数据再排成一个大顶堆,这样就找出了次大值
以此类推
虽然中间过程一直是大顶堆,最后输出总的数组时却是一个小顶堆,这样就完成了排序。
2.2 堆排序
3.3 执行结果如下:
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)
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;
- }
- 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
a. 如果在堆排序过程中有如下数据
49
65 76
49 65 76中最大的数是76,只需要将76与49交换即可,然后再调整49这一支的数据,65这一支不动即可
76
65 49
而只需要将76与49交换即可,不需要再将65与49交换.
76
49 65
3.5 代码
![](https://i-blog.csdnimg.cn/blog_migrate/f5eb4426879d9c4b4b2deb15679e0746.png)