算法之路_15、堆排序

一、解释

从前面的博客中谈到堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子,两者对左右孩子的大小关系不做任何要求。基于这些定义,对于大根堆,处于最大堆的根节点的元素一定是这个堆中的最大值。

而堆排序算法就是利用堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。

二、代码

算法思路:

  1. 将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆(代码见上篇博文算法之路_14、堆的基本操作),此堆为初始的无序区
  2. 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn)
  3. 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆(具体调整代码见上篇博文算法之路_14、堆的基本操作),然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成

	/**
	 * 堆排序
	 * 思路:将大根堆根节点位置与最后一个位置元素交换,堆大小减一(即将最大元素位置排好)
	 * 并调整根节点位置 使得剩余位置元素依旧为一个大根堆 
	 * 重复上述操作 最终堆大小为0停止 
	 */	
	public static void heapSort(int arr[],int heapSize){
		
		while (heapSize>0) {
			Sort_logarithmic_device.swap(arr, 0, --heapSize);
			HeapTools.heapify(arr, 0, heapSize);
		}
	}

 

三、时间复杂度分析

在构建堆(初始化大顶堆)的过程中,完全二叉树从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和必要的互换,对于每个非终端结点来说,其实最多进行两次比较和一次互换操作,因此整个构建堆的时间复杂度为: O(n)。大概需进行n/2 * 2 = n次比较和n/2次交换。

在正式排序时,n个结点的完全二叉树的深度为⌊log2n⌋+1,并且有n个数据则需要取n-1次调整成大顶堆的操作,每次调整成大顶堆的时间复杂度为O(log2n)。因此,重建堆的时间复杂度可近似看做: O(nlogn)。

你可能感兴趣的:(算法之路)