赞
踩
堆排序是对简单选择排序的升级版。堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
堆排序(Heap Sort)就是利用堆进行排序的方法 。基本思想:将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值。如此反复执行,就能得到一个有序序列 。
堆排序用到的一个树的性质就是:假设父节点下标为k(k>0)
,那么其左孩子下标为2*k
,右孩子下标为2*k+1
。
实现堆排序需要四步:数组转化为二叉树,最大堆调整(Heapify),创建最大堆,堆排序。
父结点下标 =【(k - 1)/ 2】、左孩子下标 =【2k + 1】、右孩子下标 =【2k + 2】
从左右孩子中选择最大的孩子结点,与父结点交换,并递归调整交换后的孩子结点
如下图,对节点【4】进行最大堆排序,与节点【6】进行交换,交换后递归调整节点【4】往下查找最大节点【7】并交换
但我们发现单对一个节点进行最大堆调整并不能使整个二叉树形成最大堆,所以我们需对末尾节点的父节点依次向前进行最大堆排序,从而使得二叉树形成最大堆。
(1)根节点为最大值,将其与末尾子节点交换,完成最大值【9】排序
(2)对根节点进行最大堆调整,以交换的末尾节点不参与调整 ,使根节点为下一个最大值
(3)不断变换,缩小最大堆调整范围,只剩根节点,完成节点排序
- 1 #include <stdio.h>
- 2 #define size 10
- 3
- 4 void Swap(int *num, int i, int j)
- 5 {
- 6 int temp;
- 7 temp = num[i];
- 8 num[i] = num[j];
- 9 num[j] = temp;
- 10 }
- 11
- 12 // 最大堆调整
- 13 void Heapify(int *num, int len, int k)
- 14 {
- 15 if (k < len)
- 16 {
- 17 int root = k; // 根结点
- 18 int lchild = 2*k + 1; // 左孩子结点
- 19 int rchild = 2*k + 2; // 右孩子结点
- 20 // 查找左右孩子结点中的最大结点
- 21 if (lchild < len && num[root] < num[lchild])
- 22 {
- 23 root = lchild;
- 24 }
- 25 if (rchild < len && num[root] < num[rchild])
- 26 {
- 27 root = rchild;
- 28 }
- 29
- 30 // 交换最大结点到根结点
- 31 if (root != k)
- 32 {
- 33 Swap(num, root, k);
- 34 // 每次交换都可能影响到对应孩子结点子树的顺序
- 35 // 所以需要对交换后的孩子结点子树进行最大堆调整
- 36 Heapify(num, len, root);
- 37 }
- 38 }
- 39 }
- 40
- 41 // 创建最大堆
- 42 void CreateHeap(int *num, int len)
- 43 {
- 44 int i;
- 45 // 最后一个结点下标
- 46 int last = len - 1;
- 47 // 最后一个结点的父结点下标
- 48 int parent = (last - 1) / 2;
- 49 // 从最后一个结点的父结点到根结点,依次进行最大堆调整
- 50 for (i = parent; i >= 0; i--)
- 51 {
- 52 Heapify(num, len, i);
- 53 }
- 54 }
- 55
- 56 // 堆排序
- 57 void HeapSort(int *num, int len)
- 58 {
- 59 // 创建最大堆并进行最大堆调整
- 60 CreateHeap(num, len);
- 61 printf("最大堆调整!\n");
- 62 int i;
- 63 // 依次取出根结点(最大值)
- 64 for (i = len - 1; i >= 0; i--)
- 65 {
- 66 // 将最大堆的根结点(最大值)换到最后一个结点
- 67 Swap(num, i, 0);
- 68 // 交换后二叉树的根结点发生了改变,故还需对根结点做最大堆调整(已交换的末尾结点不参与调整)
- 69 // 而此时根结点小于所有父结点,因而在调整时只需考虑最大孩子的分支即可
- 70 Heapify(num, i, 0);
- 71 }
- 72 }
- 73
- 74 int main()
- 75 {
- 76 int i, num[size] = {8, 4, 3, 1, 6, 9, 5, 7, 2, 0};
- 77 HeapSort(num, size);
- 78
- 79 for (i = 0; i < size; i++)
- 80 {
- 81 printf("%d ", num[i]);
- 82 }
- 83 printf("\n");
- 84 return 0;
- 85 }
- 86
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。