概念:
堆是一种完全二叉树的数据结构。堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
性质
大顶堆:每个结点的值都大于或等于该结点的左右孩子的结点值;
小顶堆:每个结点的值都小于或等于该结点的左右孩子的结点值。
将给给定无序列构造成一个大顶堆;
1、从最后一个非叶子结点开始调整,也就是下面的7;判断是否满足大顶堆的性质,满足则跳过,不满足则调整。从上往下,从左往右调整。
2、找到倒数第二非叶子结点,判断是否满足大顶堆性质,满足则跳过,很显然倒数第二个非叶子结点(也就是下面的22)满足则跳过,同理倒数第三过也是如此。判断下一个叶子结点8,不满足大顶堆性质,则需要和其左孩子结点进行交换。
3、第一遍调整完后,再回到最后一个非叶子结点进行判断,直到所有非叶子结点都满足大顶堆的性质才结束;
将给给定无序列构造成一个小顶堆;
将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素比较交换,得到第二大元素。如此反复进行交换、重建、交换。
1、从最后一个非叶子结点判断是否满足小顶堆性质,满足则只需要其叶子结点与堆顶元素进行比较交换,不需要调整;不满足需要调整;
2、倒数第二个非叶子结点不满足小顶堆性质,但因顶堆元素比它大则不调整;将顶堆元素末尾元素进行比较,大则交换,小则于其上一个元素比较,同理。这里17于3进行交换;
3、因倒数第二个非叶子结点不满足小顶堆性质,所有将3和16进行交换后顶堆元素再进行比较交换;
4、顶堆结点不满足小顶堆性质,所有将3和7进行交换;
5、 最终实现小顶堆排序
heapsort.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 void swap(int *a, int *b)
5 {
6 int temp = *b;
7 *b = *a;
8 *a = temp;
9 }
10
11 void max_heapify(int arr[], int start, int end)
12 {
13
14 // 建立父节点指向和子节点指向
15 int dad = start;
16 int son = dad * 2 + 1;
17 while (son <= end)
18 {
19 //若子节点指向在范围内才做比较
20 if (son + 1 <= end && arr[son] < arr[son + 1])
21 //先比较两个子结点大小,选择最大的
22 son++;
23 if (arr[dad] > arr[son])
24 //如果父节点大于子结点代表调整完后,直接跳出函数
25 return;
26 else
27 {
28 //否则交换父子内容在继续子结点和孙节点比较
29 swap(&arr[dad], &arr[son]);
30 dad = son;
31 son = dad * 2 + 1;
32 }
33 }
34 }
35
36 void heap_sort(int arr[], int len)
37 {
38 int i;
39 //初始化,i从最后一个父节点开始调整
40 for (i = len / 2 - 1; i >= 0; i--)
41 max_heapify(arr, i, len - 1);
42 //先将第一个元素和已安排好元素前一位做交换,再重新调整,直到排序> 完整
43 for (i = len - 1; i > 0; i--)
44 {
45 swap(&arr[0], &arr[i]);
46 max_heapify(arr, 0, i - 1);
47 }
48 }
49
50 int main()
51 {
52 int arr[] = { 90,70,80,60,10,40,20,50,30};
53 int len = (int) sizeof(arr) / sizeof(*arr);
54 heap_sort(arr, len);
55 int i;
56 for (i = 0; i < len; i++)
57 printf("%d ", arr[i]);
58 printf("\n");
59 return 0;
60 }