十九、自己动手实现排序算法(7)-------- “ Heap Sort 堆排序 ”

参考文章:

https://www.cnblogs.com/guoyaohua/p/8600214.html                  十大经典排序算法最强总结(含JAVA代码实现)

https://mp.weixin.qq.com/s/3krwgrzB6EV4HU7wI0Rm4A             堆排序就这么简单


堆排序分析:

平均时间复杂度最好情况最坏情况空间复杂度排序方式稳定性
O(n*logn)O(n*log n)O(n*log n)O(1)In-place不稳定

 堆排序原理:

       堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

温馨提示:算法描述,排序原理搞不懂,先把最大(小)堆搞明白了,然后再看这篇文章。

 

堆排序算法描述:

  • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
  • 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  • 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

 

堆排序原理图解:

 

Java 代码实现:

代码一:


package com.sorting.algorithm;

public class HeapSort {
	
	public static int[] heapSort(int[] array){
		int n = array.length;
		// 把数组堆化   heapify, 创建最大堆
		for (int i = (n-1-1)/2; i >= 0; i--) {
			siftDown(array,n,i);
		}
		
		// 将创建好的最大堆最大值放到数组最后,并重建除最大值以外的数组,建立最大堆,循环或递归进行
		for (int i = n-1; i > 0; i--) {
			swap(array,0,i);
			siftDown(array,i,0);
		}
		
		return array;
	}

	private static void swap(int[] array, int i, int j) {
		int temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}

	// 堆中原始的下沉操作
	private static void siftDown2(int[] array, int n, int k) {
		while(2*k+1 < n){
			// j 代表左右子树最大值的下标
			int j = 2*k +1;
			if(j+1 < n && array[j] < array[j+1])
				j++;
			
			// 如果父节点 大于 左右子树节点就跳出循环
			if(array[j] < array[k]) break;
			
			// 将父节点和左右子树中的最大值交换位置
			swap(array, k, j);
			
			// 迭代看子树是否需要下沉操作
			k=j;
		}
	}
	
	// 堆中改进的下沉操作
	private static void siftDown(int[] array, int n, int k) {
		int e = array[k];
		while(2*k+1 < n){
			int j = 2*k +1;
			if(j+1 < n && array[j] < array[j+1])
				j++;
			if(array[j] < array[k]) break;
			array[k] = array[j];
			k=j;
		}
		array[k] = e;
	}

	public static  void printArr(int[] array){
		for (int i = 0; i < array.length; i++) {
			if(i != array.length-1)
				System.out.print(array[i] + ",");
			else
				System.out.println(array[i]);
		}
	}
	
	public static void main(String[] args) {
		int[] array = { 58,36,70,22,88,64,1,32 };
		System.out.println("排序之前:");
		printArr(array);
		System.out.println("-------------------------------");
		
		System.out.println("排序过程");
		heapSort(array);
		
		System.out.println("-------------------------------");
		System.out.println("排序之后:");
		printArr(array);
		
	}

}

 

代码二:


package com.sorting.algorithm;

public class HeapSort2 {
	
	// 用来记录变化的数组长度
	private static int len;
	
	public static int[] heapSort(int[] array){
		
		len = array.length;
		
		// 将数组堆化
		buildMaxHeap(array);
		
		// 将最大堆中的最大值放大数组的后面,数组长度减一,并重建最大堆 ,循环遍历,知道完成排序
		while(len > 0){
			printArr(array);
			swap(array,0,len-1);
			len--;
			printArr(array);
			adjustHeap(array,0);
		}
		
		return array;
	}

	// 调整最大堆,使它符合最大堆的性质
	private static void adjustHeap(int[] array, int i) {
		int maxIndex = i;
		if(2*i <len && array[maxIndex] < array[2*i])
			maxIndex = 2*i;
		if(2*i+1 <len && array[maxIndex] < array[2*i+1])
			maxIndex = 2*i+1;
		
		// 递归调用 adjustHeap ,让父节点,左右子树都符合最大堆的性质
		if(maxIndex != i){
			swap(array, i, maxIndex);
			adjustHeap(array, maxIndex);
		}
		
	}

	private static void swap(int[] array, int i, int j) {
		int temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}

	// 将数组堆化
	private static void buildMaxHeap(int[] array) {
		int n = array.length;
		for(int i = n/2; i >= 0; i--){
			adjustHeap(array,i);
		}
	}
	
	public static  void printArr(int[] array){
		for (int i = 0; i < array.length; i++) {
			if(i != array.length-1)
				System.out.print(array[i] + ",");
			else
				System.out.println(array[i]);
		}
	}
	
	public static void main(String[] args) {
		int[] array = { 58,36,70,22,88,64,1,32 };
		System.out.println("排序之前:");
		printArr(array);
		System.out.println("-------------------------------");
		
		System.out.println("排序过程");
		heapSort(array);
		
		System.out.println("-------------------------------");
		System.out.println("排序之后:");
		printArr(array);
		
	}
	
}

 

 

堆排序代码测试:

代码一:

 

 

代码二:

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值