交换排序图解_算法导论学习笔记(五)堆排序

一、基础知识

下标为i的节点的父节点下标:(i-1)/2

下标为i的节点的左孩子下标: i*2+1

下标为i的节点的右孩子下标: i*2+2

二、堆排序执行过程(大顶堆)

arr[5]={3,5,4,2,9}

721289577ad7af0997791e714c4f03b0.png
原始堆
  1. 建堆
for(i=n/2-1;i>=0;i--) //i=n-1,下标为=n-1-1=n-2 
	 {
	 	heapify(arr,n,i); //对每个结点的左右孩子以及自身进行排序操作,调整性质 
                                  //注意在建堆过程中,和哪个节点发生了交换,就要把交换的节点heapify一次,维持他的性质
	 } 

PS:建堆时从第一个有孩子节点的开始交换,所以令i=n/2,又因为数组下标是从零开始的,所以再减去1

eee4cfbabcc209f28a94bbcf6de7a014.png
建堆完整过程

2.排序

for(i=n-1;i>0;i-- ){
		swap(&arr[i],&arr[0])//就是把最大的拿掉,放到数组最后已排好序的序列中。把最小的放到堆顶,下一步调整堆 
		heapify(arr,i,0) 
}

a4fa400ff5f5d5f5f2578d4aa41f8e55.png

三、堆排序代码

void heapify(int arr[],int n,int i)      //维护堆的性质 
{
	int largest = i;
	int lson = i*2+1;
	int rson = i*2+2;
	
	if(lson < n&&arr[largest]<arr[lson])
	{
		largest = lson;
	}
	if(rson < n&&arr[largest]<arr[rson])
	{
		largest = rson;
	}
	if(largest ! =i){
		swap(&arr[largest],&arr[i]);
		heapify(arr,n,largest)             //交换节点后破坏了堆的性质,要重新维护一下
                                                   //注意此处传入的是largest,就算法执行第一轮来说是最后一个节点也就是说此处heapify执行不了,无左右孩子不需要维护 
	}
 } 
 
 //堆排序入口
 void heap_sort(int arr[],int n){
 	int i;
 	//建堆
	 for(i=n/2-1;i>=0;i--) //此处是从第一个有孩子节点的地方开始调整。之所以要减一是因为用数组存储的
	 {
	 	heapify(arr,n,i); //对每个结点的左右孩子以及自身进行排序操作,调整性质 
	 } 
	//排序 
	for(i=n-1;i>0;i-- ){
		swap(&arr[i],&arr[0])//就是把最大的拿掉,放到数组最后已排好序的序列中。把最小的放到堆顶,下一步调整堆 
		heapify(arr,i,0)    //交换后要对数组重新进行维护操作
                                   //注意此处传进去的是i,也就是每执行一次,数组长度就减一
	}
 } 

四、时间复杂度和稳定性

时间复杂度为:O(NlogN)

  1. 建堆复杂度为O(N)
  2. heapify复杂度为O(logN)
  3. 堆排序对N个数进行heapify

稳定性:是不稳定的


两个需要注意的地方!

1️⃣建堆是从n/2-1开始heapify

2️⃣排序是是从根节点开始heapify!


参考

排序算法:堆排序【图解+代码】_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值