排序算法:堆排序

堆排序:不稳定排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树

 思想:初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个 堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对 它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。

时间复杂度:

最差:O(nlog2n)

平均:O(nlog2n)

最好:O(nlog2n)

空间复杂度: O(1)

package test;

import java.util.Arrays;
/*
 * 堆排序
 * 大顶堆的特点:父节点比左右节点的值都大的完全二叉树
 * 数组中可以按下标来确定在二叉树的位置,例如,位置为i的父节点,其子节点位置是2*i 和 2*i+1
 * 所以可以直接将数组当成二叉树来处理,不用另外建树。注意,数组的第一个元素A[0] 不在二叉树的范围内
 * 二叉树应满足 父节点 大于子节点,所以从最后一个非叶节点开始往前遍历,来调整堆
 * (注意:当交换节点位置时,需要重新调整子节点树,因为经过交换后,其子树可能不符合堆的要求)
 * 
 * 当二叉树满足大顶堆时,堆顶的元素就是最大的元素。从而可以利用这个来排序
 * 将堆顶元素与对的最后一个元素交换,然后对前面(n-1)个元素重新调整,就可以变成新的堆。重复交换即可排序
 */
public class HeapSort {
	//调整堆的函数,i为需要调整的子树的父节点
	static void heapAdjust(int a[], int i, int size) {
		//左右节点的下标
		int l = 2* i;
		int r = 2*i + 1;
		//寻找父节点,左节点,右节点中最大的元素的下标,注意左右节点的下标不能越界
		int max = i;
		if(l <= size && a[l] > a[max]) {
			max = l;
		}
		if(r <= size && a[r] > a[max]) {
			max = r;
		}
		//max != i 表明父节点不是最大的,需要交换该子节点A[max] 和父节点,并且重新调整该子节点的子树
		if(max != i) {
			int temp = a[i];
			a[i] = a[max];
			a[max] = temp;
			//调整子节点的子树
			heapAdjust(a,max,size);
		}
		
	}
	
	//建堆函数:初始化数组时,从最后一个非叶子节点开始往前扫描,逐一调整堆,直到A[1],表明建堆完毕
	static void heapBuild(int a[], int size) {
		for(int i = size/2; i >= 1; i--) {
			heapAdjust(a,i,size);
		}
	}
	
	//堆排序函数
	static void heapSort(int a[], int size) {
		//首先建堆
		heapBuild(a,size);
		//从最后一个元素开始,与堆顶元素交换,得到最大的数。前面n-1个数重新调整为堆,再继续交换
		for(int i = size; i >= 1; i--) {
			int temp = a[1];
			a[1] = a[i];
			a[i] = temp;
			heapAdjust(a,1,i-1);
		}
	}
	
	public static void main(String args[]) {
		int a[] = new int[]{0,16,7,3,20,17,8};
		heapSort(a,6);
		System.out.println(Arrays.toString(a));
	}
	
}



猜你喜欢

转载自blog.csdn.net/linyk3/article/details/48177881