您的位置:首页 > 编程语言 > Java开发

堆排序-java

2016-02-22 20:40 323 查看

堆排序-java

转载请注明出处:http://blog.csdn.net/a740169405/article/details/50718944

思想:

前面的文章有选择排序,我们每次都要从剩余的数组中找出最小值,这样每次比较都会有重复的操作。

如果我们能记录下最小的值,将提高选择效率,从而提高算法的效率。

堆排序把待排序的数组转化为完全二叉树的结构,并按照层级关系对每个节点赋值下标。

其中涉及到了大顶堆和小顶堆的概念,即

完全二叉树的双亲节点与孩子之间的下标存在关系:如果结点i = 0,则其无双亲,如果i > 1,

则其双亲为:


堆排序不断的将二叉树变成大顶堆,然后将根节点和末尾节点交换,接着继续将二叉树变成大顶堆,

如此往复,直到排序完成。

循环方式实现:

/**
* 堆排序
*/
private static void heepSort(int[] arr) {
int i;
for (i = arr.length / 2; i >= 0; i--) {
// 之所以从中间到最小,是因为中间到最小这些下标都不是叶子节点
heapAdjust(arr, i, arr.length - 1);
}

for (i = arr.length - 1; i > 0; i--) {
// 交换根节点与末尾元素互换
swap(arr, 0, i);
// 重新调整大顶堆
heapAdjust(arr, 0, i - 1);
}
}


这里有一个方法,就是heapAdjust方法,它是用来把当前数组排成大顶堆的方法:

private static void heapAdjust(int[] arr, int i, int count) {
int tmp = arr[i];  // 先把双亲节点记录下来
for (int j = i * 2; j <= count; j*=2) {
// 每次跳跃的值为2j,原因是完全二叉树中,(双亲节点下标 = 左孩子 * 2)
if (j <= count - 1 && arr[j + 1] > arr[j]) {
// 当右孩子比左孩子大时,需要把下标移到右孩子那
++j;
}
if (arr[j] <= tmp) {
// 如果两个孩子中最大的那个都比双亲节点小,则此次不做调整
break;
}
// 把较大的那个孩子和双亲节点对换
arr[i] = arr[j];
// 把i赋值成较大的那个孩子的下标,让循环结束后双亲节点跑到下面去
i = j;
}
// 移动(也有可能不移动)双亲节点到下面
arr[i] = tmp;
}


还有一个交换方法:

private static void swap(int[] arr, int l, int r) {
int tmp = arr[l];
arr[l] = arr[r];
arr[r] = tmp;
}


调用方法:

int[] arr = new int[] {1, 45, 78, 23, 12, 98, 150, 1, 45};
heepSort(arr);
System.out.println(Arrays.toString(arr));


结果:



复杂度分析:



稳定性分析:

由于堆排序是跳跃式交换数据,所以是不稳定的算法

参考:《大话数据结构》书籍
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: