• 排序算法---堆排序


    github:代码实现
    本文算法均使用python3实现


    1. 什么是堆

      堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象,且堆总是一棵完全二叉树。由于堆是基于完全二叉树的结构,因此可以使用顺序存储结构数组来保存堆,再根据堆的性质,我们可以得到该数组(从0下标开始)的一些性质
      (1)对于数组 $ heap $ 中的第 $ i $ 个节点,其左孩子节点值 $ heap[2i+1] leq heap[i] $ 且其右孩子节点值 $ heap[2i+2] leq heap[i] $ ,此时为大根堆。(父亲值大于等于孩子值)
      (2)对于数组 $ heap $ 中的第 $ i $ 个节点,其左孩子节点值 $ heap[2i+1] geq heap[i] $ 且其由孩子节点值 $ heap[2i+2] geq heap[i] $ ,此时为小根堆。(父亲值小于等于孩子值)

    ![](https://images2018.cnblogs.com/blog/1238724/201806/1238724-20180611162232646-1848476154.jpg)
      对于**大根堆**,将其映射到数组中如下:
    ![](https://images2018.cnblogs.com/blog/1238724/201806/1238724-20180611162239577-1334425849.jpg)

    2. 如何构建初始堆

      的构建是一个递归的过程。下面以大根堆为例进行讲解。具体操作如下:
      构建初始大根堆:从最后一个非叶子节点开始,比较其与其左右孩子值的大小,若其节点值比孩子节点值小,则将其与较大孩子进行交换。然后依次对其它节点进行如此比较与交换,直至根节点,此时根节点的值即为该堆中的最大值。

    ![](https://images2018.cnblogs.com/blog/1238724/201806/1238724-20180611164124620-102513422.jpg)

    3. 如何进行堆排序

      堆排序是在已经构建好的初始大根堆上进行。主要分为以下几步:
      (1)对初始序列构建初始大根堆。(按照2中所描述)
      (2)将大根堆的根节点值最后一个节点值交换。

    ![](https://images2018.cnblogs.com/blog/1238724/201806/1238724-20180611174412503-347451058.jpg)
      (3)将交换后的堆从**数组**上分为两个区:无序区与有序区。对无序区进行**“堆调整”**,即将无序区调整为大根堆。(其实建立**初始大根堆**也是一个不断调用**“堆调整”**的过程)
    ![](https://images2018.cnblogs.com/blog/1238724/201806/1238724-20180611174422971-556771902.jpg)

      (4)将无序区中的根节点值与无序区中的最后一个节点值进行交换。此时无序区长度减 $ 1 $ ,有序区长度加 $ 1 $ ,见下图。重复(3)直到无序区中只有一个节点为止。
    ![](https://images2018.cnblogs.com/blog/1238724/201806/1238724-20180611171306482-1740154221.jpg)

    4. 实现代码

    class HeapSort:
    	'''堆排类'''
    	def Max_Heapify(self, heap, heapsize, root):
    		'''堆调整,使得根节点值大于子节点值'''
    		left = root * 2 + 1  # 列表从0开始,左节点下标为 2i+1,右节点下标为 2i+2
    		right = left + 1
    		larger = root
    		if left < heapsize and heap[left] > heap[larger]:
    			larger = left
    		if right < heapsize and heap[right] > heap[larger]:
    			larger = right
    		if larger != root:
    			heap[larger], heap[root] = heap[root], heap[larger]
    			self.Max_Heapify(heap, heapsize, larger)
    		else: return 
    
    	def Build_Max_Heap(self, heap):
    		'''构建初始大根堆'''
    		heapsize = len(heap)
    		for i in range((heapsize-2)//2, -1, -1):
    			# 从最后一个非叶子节点开始构建
    			self.Max_Heapify(heap, heapsize, i)
    
    	def Heap_Sort(self, heap):
    		'''堆排序'''
    		# 步骤(1)构建初始大根堆
    		self.Build_Max_Heap(heap)
    		for i in range(len(heap)-1, -1, -1):
    			# 步骤(2)交换无序区第一个节点值与最后一个节点值
    			heap[0], heap[i] = heap[i], heap[0]
    			# 步骤(3)对无序区进行“堆调整”
    			self.Max_Heapify(heap, i, 0)
    		return heap[::-1]
    
    

    5. 算法分析

      堆排序是一种选择排序,且是不稳定排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆的时间复杂度为 $ O(n) $ ,在交换并重建堆的过程中,需进行 $ n-1 $ 次”堆调整”,而重建堆的过程中,根据完全二叉树的性质,$ [log_2(n-1),log_2(n-2)...1] $ 逐步递减,近似为 $ O(n log_2 n) $ 。所以堆排序时间复杂度为是 $ O(n log_2 n) + O(n) = O(n log_2 n) $ 。即堆排序的最坏时间复杂度为 $ O(n log_2 n) $ (平均复杂度接近于最坏情况)。


    引用及参考:
    [1]《数据结构》李春葆著
    [2] https://www.cnblogs.com/chengxiao/p/6129630.html
    [3] https://blog.csdn.net/minxihou/article/details/51850001

    写在最后:本文参考以上资料进行整合与总结,属于原创,文章中可能出现理解不当的地方,若有所见解或异议可在下方评论,谢谢!
    若需转载请注明https://www.cnblogs.com/lliuye/p/9167471.html

  • 相关阅读:
    第二十二篇 正在表达式 re模块
    机器学习 —— 概率图模型(推理:采样算法)
    机器学习 —— 概率图模型(推理:MAP)
    机器学习 —— 概率图模型(推理:团树算法)
    机器学习 —— 概率图模型(推理:消息传递算法)
    第二次读书会的思考
    机器学习 —— 概率图模型(推理:变量消除)
    机器学习 —— 概率图模型(马尔科夫与条件随机场)
    机器学习 —— 概率图模型(CPD)
    机器学习 —— 概率图模型(贝叶斯网络)
  • 原文地址:https://www.cnblogs.com/lliuye/p/9167471.html
Copyright © 2020-2023  润新知