您的位置:首页 > 其它

排序算法---堆排序

2017-12-01 15:36 274 查看
堆是一种特殊的数据结构,首先堆是一个完全二叉树,所有堆满足所有二叉树的特定,对于大顶堆,最大数应用再一位,所有如果向对一个数组排序,可以将堆顶和最后一个元素交换,之后再次调整堆,直到堆元素个数为1,所有堆排序算法很简单:

1. 将数组构建成一个堆(生序:大顶堆,降序:小顶堆)

2. 交换堆顶和最后一个元素

3. 迭代1,2步,直到所有元素排序完成

代码实现如下:

package algorithm.sort;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
* 堆排序
* 堆性值:
* 大顶堆  a[i] >= a[i2+1] && a[i] >= a[i2+2]
* 小顶堆  a[i] <= a[i2+1] && a[i] <= a[i2+2]
* 先构建大顶堆或者小顶堆,之后交换堆顶和最后一个元素,在堆N-1个元素重新构建堆,直到堆有序
* 时间复杂度O(nlogn)
*/
public class HeapSort {

public static AtomicInteger n = new AtomicInteger(0);

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

/**
* 构建大顶堆 算法实现:
* 1. 从堆的最后一个非子节点开始(arr.length/2-1),直到第一个元素开始遍历
* 2. 让非子节点和它的子节点比较,选取出最大值
* 3. 更新最大值到当前非子节点
* 4. 再次使用以上步骤,更新子节点,直到最后一个非子节点
*
* @param arr         需要构建的数组
* @param parentIndex 当前处理的非子节点
* @param endIndex    数组长度,该参数主要用于堆排序,构建堆其实不需要该参数
*/
public static void adjuestHead(int[] arr, int parentIndex, int endIndex) {
//保存当前节点
int tmp = arr[parentIndex];
// 非子节点第一个孩子
int childIndex = parentIndex * 2 + 1;
while (childIndex < endIndex) {
// 判断是否有两个孩子
if (childIndex + 1 < endIndex && arr[childIndex] < arr[childIndex + 1]) childIndex += 1;
//如果父节点大于子节点,则直接退出
if (tmp >= arr[childIndex]) break;
arr[parentIndex] = arr[childIndex];
//继续堆子节点调整
parentIndex = childIndex;
childIndex = childIndex * 2 + 1;
}
arr[parentIndex] = tmp;
}

public static void maxHeadHeap(int[] arr) {
// 第一个非叶子节点,从下至上,从右至左
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjuestHead(arr, i, arr.length);
}
}

public static void headSort(int[] arr) {
//初始并构建大顶堆
maxHeadHeap(arr);

for (int index = arr.length - 1; index >= 0; index--) {
//交换堆顶和最后一个元素
swatch(arr, 0, index);
//重新调整剩余堆元素
adjuestHead(arr, 0, index);
}

}

public static void main(String[] args) {
int data_len = 100000;
int[] data = new int[data_len];
Random rd = new Random();
for (int index = 0; index < data_len; ) {
data[index++] = rd.nextInt(10000);
}
System.out.println("生成数据完成");
//        showData(data);
long start = System.currentTimeMillis();
headSort(data);
System.out.printf("堆排序算法\t运行时间%dms\n", (System.currentTimeMillis() - start));
showData(data);

}

public static void showData(int[] data) {
for (int item : data) {
System.out.printf("%d,", item);
}
System.out.println();
}
}


堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素+重建堆组成,其中堆构建的时间复杂度O(n),交换并重建需要交换n-1次,重建堆过程,根据二叉树性值为nlogn,所以堆排序时间负责度一般认为是O(nlogn)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: