栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

手撕堆排序

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手撕堆排序

我是根据b站上python数据结构里写的
https://www.bilibili.com/video/BV1uA411N7c5?p=19&vd_source=02a4e8285fe8de80a417aeb3344debc0

网上有很多关于堆排的,我这里就不重复了,写点不一样的。

堆排原理,建堆-》出数——》向下调整(我看算法导论里叫维护堆,差不多一个意思)

堆是一种树,有大堆小堆,大堆就是父节点比子节点大.
也就是说,建完堆,堆顶是最大的,每次取堆顶交换数组最后一个(没排序的最后一个),就能排好。
父节点是(子节点-1)//2
左子节点是2父+1,右子节点是2父+2
太多我就不说了,可以看看其他博客,这里说点别的地方没有的。
https://blog.csdn.net/qq_28063811/article/details/93034625/

步骤

1.建堆

建堆用向下调整也叫堆维护,建立个大堆
就是重第一非叶子节点开始,循环维护向下调整后,数组就是大堆。
数学证明算法导论中有,我还没看。
大概就是,重一开个小堆开始,向下调整,还挺不好理解的暂时相信它是对的。

向下调整的代码

def sift(li,low,high):
	i =low #堆顶指针1
	j = 2*i+1 # 指针2
	tmp = li[low] #需要比较的数
	while j<= high: #指针2别出界,出界就停了
		if j+1 <=high and li[j+1]>li[j]: #有没有右子节点,有右子节点的话比较,让j指针是大的那个
			j = j+1
		if  tmp < li[j]: # 比较两个指针大小,做出是否交换,和向下
			li[i] = li[j]
			i = j
			j = 2*i+1
		else:
			li[i] = tmp #发现它是最大的,不用比了,停止,把tmp放在这层
			break
	else:
		li[i] = tmp #循环完了,没有可以比的了,把tmp放在这
		

两个
就是两个指针比较,当然每一层实际上是三个数比较

左节点和右节点比较,找到大的,变成j,和tmp比较

如果j大把li[j]的值给到i的位置

如果停止了(可能是到底了,也可能是tmp比下面都大了),总之停止了,就把li[i] =tmp,把tmp放在这就行。

建堆代码

def hip_sort(li):
	n = len(li)
	for i in range((n-1-1)//2,-1,-1):
		sift(li , i, n-1) #每次的low就是每个非叶子节点,一直到0,high就是让它别出界就行,到n-1
	

先找到最后一个叶子节点,就是最后一个数它的父节点,最后一个数下标是数组长度-1,
它的父节点是(n-1-1)//2
python的//是除法并向下取整,就是啥意思,如果是左 ,减一处2后,应该是个整数,那就是它,
如果是右,减一处2,可能带个0.5,因为是向下取证,那还是它

因为python语法,右括号的-1是不包含-1的,到0,注意一下

2.出数并向下调整
	for j in range(n-1,0,-1): # 从最后一个数,到倒数第二个(我感觉li[0]没必要和li[0]交换)
		li[0],li[j] = li[j],li[0] #交换
		
		sift(li,0,j-1) #向下调整,注意一下调整需要的high是j-1,交换完了,需要调整的数组就少了一个数

写的不太好,变革口诀吧

def sift(li,low,high):
	i =low
	j = 2*i+1
	tmp = li[low]
	while j<= high:
		if j+1 <=high and li[j+1]>li[j]:
			j = j+1
		if  tmp < li[j]:
			li[i] = li[j]
			i = j
			j = 2*i+1
		else:
			li[i] = tmp
			break
	else:
		li[i] = tmp



def hip_sort(li):
	n = len(li)
	for i in range((n-1-1)//2,-1,-1):
		sift(li , i, n-1)
	for j in range(n-1,0,-1):
		li[0],li[j] = li[j],li[0]
		sift(li,0,j-1)

建堆出数加调整,最后非叶子节点调到0.
0和堆的最后一个换,再调整。
一个i一个j双指针,i是根j是它子节点
while一循环,防止出界j小于等于high。
如果有右子节点,选出左右最大数下标。
如果子大于tmp,就交换到i位置。
并子变父,生成新子,否则停止tmp放在i。
停了就把tmp放i那。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/994593.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号