欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

堆排序及代码实现

程序员文章站 2022-06-06 20:41:15
...

堆排序

堆的先验知识:

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

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

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

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

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

并且,父亲节点和子节点有如下关系:父亲节点的下标如果为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))
相关标签: leetcode