堆排序(C语言)

堆排序(C语言实现)

堆排序是对简单选择排序的升级版。堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

堆排序算法 

堆排序(Heap Sort)就是利用堆进行排序的方法 。基本思想:将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值。如此反复执行,就能得到一个有序序列 。

堆排序用到的一个树的性质就是:假设父节点下标为k(k>0),那么其左孩子下标为2*k,右孩子下标为2*k+1

实现堆排序需要四步:数组转化为二叉树最大堆调整(Heapify)创建最大堆堆排序

一、数组转化为二叉树

父结点下标 =【(k - 1)/ 2】、左孩子下标 =【2k + 1】、右孩子下标 =【2k + 2】

二、最大堆排序 (Heapify)

从左右孩子中选择最大的孩子结点,与父结点交换,并递归调整交换后的孩子结点

如下图,对节点【4】进行最大堆排序,与节点【6】进行交换,交换后递归调整节点【4】往下查找最大节点【7】并交换

三、创建最大堆(CreateHeap)

但我们发现单对一个节点进行最大堆调整并不能使整个二叉树形成最大堆,所以我们需对末尾节点的父节点依次向前进行最大堆排序,从而使得二叉树形成最大堆。

 

四、堆排序

(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 

代码结果

  • 38
    点赞
  • 186
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
堆排序是一种基于堆数据结构的排序算法,其时间复杂度为O(nlogn)。下面是C语言实现堆排序的代码: ```c #include <stdio.h> // 交换两个元素 void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } // 调整堆 void heapify(int arr[], int n, int i) { int largest = i; // 最大值 int left = 2 * i + 1; // 左子节点 int right = 2 * i + 2; // 右子节点 // 如果左子节点比当前节点大,则更新最大值 if (left < n && arr[left] > arr[largest]) largest = left; // 如果右子节点比当前节点大,则更新最大值 if (right < n && arr[right] > arr[largest]) largest = right; // 如果最大值不是当前节点,则交换元素并继续调整堆 if (largest != i) { swap(&arr[i], &arr[largest]); heapify(arr, n, largest); } } // 堆排序 void heapSort(int arr[], int n) { // 构建堆(从最后一个非叶子节点开始) for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i); // 逐个提取元素并调整堆 for (int i = n - 1; i >= 0; i--) { swap(&arr[0], &arr[i]); // 将当前最大值移动到数组末尾 heapify(arr, i, 0); // 调整堆 } } // 测试代码 int main() { int arr[] = {12, 11, 13, 5, 6, 7}; int n = sizeof(arr) / sizeof(arr[0]); heapSort(arr, n); printf("排序后的数组:\n"); for (int i = 0; i < n; i++) printf("%d ", arr[i]); printf("\n"); return 0; } ``` 代码中,`heapify`函数用于调整堆,`heapSort`函数用于进行堆排序。首先构建堆,然后逐个提取元素并调整堆,最终得到有序数组。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值