堆排序及代码实现

堆排序

堆的先验知识:

堆的实现通常是通过构造二叉堆实现。当不加限定时,堆通常指的就是二叉堆。

二叉堆一般分为两种:最大堆和最小堆。

最大堆: 最大堆中的最大元素在根结点(堆顶);堆中每个父节点的元素值都大于等于其子结点;

最小堆: 最小堆中的最小元素出现在根结点(堆顶);堆中每个父节点的元素值都小于等于其子结点。

二叉堆是一种完全二叉树,对于完全二叉树来说,只有树🌲的最后一层的节点不是满的,其他层都是满的,完全二叉树采用顺序存储,利用数组进行实现;

并且,父亲节点和子节点有如下关系:父亲节点的下标如果为i,则左右子节点的下标分别为2*i+ 1,2 * i + 2。

构建一个大顶堆采用下沉调整:从第一个非叶子节点开始,从右至左依次调整节点;

图如下所示:图参考自:https://www.cnblogs.com/chengxiao/p/6129630.html

在这里插入图片描述
在这里插入图片描述
第一个非叶子节点的下标为arr.length/2 - 1

代码逻辑:

对于每一个父亲节点,首先找到其左孩子的下标,然后判断是否有右孩子,如果有,比较一下左右孩子的大小,

如果由右孩子大于左孩子,

​---------------则比较父亲节点和右孩子的大小(因为父亲节点要大于任何一个孩子),如果父亲节点大于右孩子(则父亲节点大于任何一个孩子),无需下沉父亲节点;否则,进行下沉;

如果右孩子小于左孩子,

​--------------则比较父亲节点和左孩子的大小(因为父亲节点要大于任何一个孩子),如果父亲节点大于左孩子(则父亲节点大于任何一个孩子),无需下沉父亲节点;否则,进行下沉;

代码实现如下所示:(构建一个大根堆)

##下沉调整
    	def adjustHeap(self, parent_index, length):
    		temp = arr[parent_index]
    		child_index = 2 * parent_index + 1
    		

    		#构建大根堆
    		while child_index < length:

    			##如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子
    			if child_index + 1 < length and arr[child_index] < arr[child_index + 1]:
    				child_index += 1

    			#构建大根堆
    			#如果父节点大于任何一个孩子的值,则不进行交换,直接跳出
    			if arr[child_index] < temp:
    				break
          
    			#下面对父节点进行下沉,单向交换;
    			arr[parent_index] = arr[child_index]
    			parent_index = child_index
    			child_index = 2 * child_index + 1

    		arr[parent_index] = temp
构建一个小根堆的逻辑:

从第一个非叶子节点开始,从右向左进行调整;

找到父亲节点的左孩子,然后判断左孩子和右孩子的大小,

如果左孩子小于右孩子,
----------------则比较父亲节点和右孩子的大小,如果小于右孩子,则小于任何一个孩子节点,不进行交换,否则,进行交换;

如果左孩子大于右孩子,

​---------------则比较父亲节点和左孩子的大小,如果小于左孩子,则小于任何一个孩子节点,不进行交换,否则,进行交换;

代码如下:

class Solution:
    def getLeastNumbers(self, arr, k):

    	if k == 0:
    		return arr[k:k]


    	##下沉调整,构建一个小根堆

    	def adjustHeap(self, parent_index, length):
    		temp = arr[parent_index]
    		child_index = 2 * parent_index + 1
    		

    		#构建小根堆
    		while child_index < length:

    			##如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子
    			if child_index + 1 < length and arr[child_index] > arr[child_index + 1]:
    				child_index += 1

    			#构建小根堆
    			#如果父节点小于任何一个孩子的值,直接跳出
    			if temp <= arr[child_index]:
    				break
    			
    			arr[parent_index] = arr[child_index]
    			parent_index = child_index
    			child_index = 2 * child_index + 1

    		arr[parent_index] = temp

堆排序

首先对于给定数组构建一个堆,如果是升序我们就构建一个大根堆;

然后交换堆顶和最后一个叶子节点的值,之后重新调整堆(不包括最后一个叶子节点),使其符合大根堆的结构;这样堆顶就是这个数组中次大的元素;

之后重复步骤二,就可以获得排序数组;

代码如下所示:

class Solution:
    def getLeastNumbers(self, arr, length):

    	##下沉调整
    	def adjustHeap(self, parent_index, length):
    		temp = arr[parent_index]
    		child_index = 2 * parent_index + 1
    		

    		#构建大根堆
    		while child_index < length:

    			##如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子
    			if child_index + 1 < length and arr[child_index] < arr[child_index + 1]:
    				child_index += 1

    			#构建大根堆
    			#如果父节点大于任何一个孩子的值,直接跳出
    			if arr[child_index] < temp:
    				break
    			
    			arr[parent_index] = arr[child_index]
    			parent_index = child_index
    			child_index = 2 * child_index + 1

    		arr[parent_index] = temp


    	# arr = [2,3,4,5,6,7,1]

    	#构建堆
    	for i in range(len(arr)//2 - 1, -1, -1):
    		adjustHeap(self, i, len(arr))

    	print(arr)



    	#调整堆结构
    	for j in range(len(arr) - 1, 0, -1):

    		#交换
    		temp1 = arr[0]
    		arr[0] = arr[j]
    		arr[j] = temp1

    		adjustHeap(self, 0, j)


    	print("#####")
    	print(arr)

if __name__ == '__main__':

	arr = [2,3,4,5,6,7,1]
	so = Solution()
	so.getLeastNumbers(arr,len(arr))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值