排序算法 之 (直接插入排序)
10.6、堆排序
对于n个关键字序列L[1...n],满足下面某一条性质,则称为堆(Heap)
- 若满足:且, ,大根堆(大顶堆)
- 若满足:且, ,小根堆(小顶堆)
这里需要了解二叉树的顺序存储,对于n个结点的关键字来说
这里就是叶子结点,
这里就是分支结点(非叶子结点);
分支结点的,左孩子:,右孩子:
大根堆: 左孩子、右孩子 父节点
小根堆:父节点 左孩子、右孩子
堆排序是不稳定的
图解大根堆、小根堆
那么应该如何建立大根堆(小根堆)了;
思路:看非叶子结点是否满足大根堆(小根堆)要求,如果不满足进行调整
图解过程
小根堆的建立也差不多;
大根堆的排序过程图解
首先,就是交换大根堆堆顶元素和最后一个为排序的元素,交换后最后一个就是该元素的排序的位置,现在需要堆顶元素进行大根堆化;然后重复操作直到全部排序完成
大(小)根堆排序的代码实现
#include <stdio.h> #include <stdlib.h> #define boolean int #define false 0; #define true 1; //大根堆排序,将以k为根的子树调整为大根堆 void HeadAdjust(int nums[],int k,int len){ int temp = nums[k];//暂存子树的根结点 for(int i=2*(k+1)-1;i <= len;i = i*2 + 1){//沿着k较大的结点,向下筛选 if(i < len && nums[i] < nums[i+1]){//看左孩子和右孩子那个大,取那个 i++; } if(temp >= nums[i]) break;//根结点大,就不需要交换,返回 else{ nums[k] = nums[i]; //否则交换 k = i; //修改k值,继续向下筛选 } } nums[k] = temp; //被筛选的结点放入最终位置 } //建立大根堆 void BuildMaxHeap(int nums[] ,int length){ for(int i = length/2-1;i>=0;i--){ //从后往前非叶子结点进行大根堆初始化 HeadAdjust(nums,i,length-1); } } //堆排序(大根堆) void MaxHeapSort(int nums[],int length){ BuildMaxHeap(nums,length);//建立大根堆 for(int i = length-1;i > 0;i--){ //交换堆顶和堆堆尾 int temp = nums[i]; nums[i] = nums[0]; nums[0] = temp; HeadAdjust(nums,0,i-1);//把新的堆变成大根堆 } } //小根堆排序,将以k为根的子树调整为小根堆 void HeadAdjust1(int nums[],int k,int len){ int temp = nums[k];//暂存子树的根结点 for(int i=2*(k+1)-1;i <= len;i = i*2 + 1){//沿着k较大的结点,向下筛选 if(i < len && nums[i] > nums[i+1]){//看左孩子和右孩子那个大,取那个 i++; } if(temp <= nums[i]) break;//根结点大,就不需要交换,返回 else{ nums[k] = nums[i]; //否则交换 k = i; //修改k值,继续向下筛选 } } nums[k] = temp; //被筛选的结点放入最终位置 } //建立小根堆 void BuildMinHeap(int nums[] ,int length){ for(int i = length/2 - 1;i>=0;i--){ //从后往前非叶子结点进行大根堆初始化 HeadAdjust1(nums,i,length-1); } } //堆排序(小根堆) void MinHeapSort(int nums[],int length){ BuildMinHeap(nums,length);//建立大根堆 for(int i = length-1;i > 0;i--){ //交换堆顶和堆堆尾 int temp = nums[i]; nums[i] = nums[0]; nums[0] = temp; HeadAdjust1(nums,0,i-1);//把新的堆变成大根堆 } } int main(){ int nums[] = {53,17,78,9,45,65,87,32}; int length = 8; printf("堆(大根堆)排序前:"); for(int i = 0; i < length ;i++){ printf("%d ",nums[i]); } MaxHeapSort(nums,length); printf("\n"); printf("堆(大根堆)排序后:"); for(int i = 0; i < length ;i++){ printf("%d ",nums[i]); } printf("\n"); int nums1[] = {49,38,65,97,76,13,27,47,89,13,48,76,88,88,99}; int length1 = 15; printf("堆(小根堆)排序前:"); for(int i = 0; i < length1 ;i++){ printf("%d ",nums1[i]); } MinHeapSort(nums1,length1); printf("\n"); printf("堆(小根堆)排序后:"); for(int i = 0; i < length1 ;i++){ printf("%d ",nums1[i]); } return 0; } //结果: 堆(大根堆)排序前:53 17 78 9 45 65 87 32 堆(大根堆)排序后:9 17 32 45 53 65 78 87 堆(小根堆)排序前:49 38 65 97 76 13 27 47 89 13 48 76 88 88 99 堆(小根堆)排序后:99 97 89 88 88 76 76 65 49 48 47 38 27 13 13
堆中插入一个新的元素
对于小根堆而言,新元素放到表尾,与父节点 这个结点进行对比,如果比父结点小就交换,交换后,继续与交换后的父结点对比,直到比它小或者到根了就结束
堆中插入一个元素图解
堆中删除一个元素
删除的元素如果不是最后一个,就使用最后一个代替它,然后对它进行小根堆化
堆中删除元素的图解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)