您的位置:首页 > 其它

排序算法:堆排序

2015-09-02 14:35 405 查看
堆排序:不稳定排序

堆排序(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));
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: