堆排序的时间复杂度是:线性对数阶 o(nlong)
一、大小堆定义
大堆:父节点都大于或等于子节点
小堆:父节点都小于或等于子节点
二、二叉排序树
首先要学习堆排序需要了解二叉排序树
二叉排序树的规律:
1.左子节点的值等于:n*2+1
2.右子节点的值等于:n*2+2
3.第n个元素的父节点的值等于:(n-1)/2
三、堆排序方法执行之前需要将数组调整成大顶堆
思想是:
1.先取出当前的元素临时存起来
2.开始循环,循环开始从左子树开始,就是顺序二叉树左子树规律:k = k*2+1,步长也是左子树
1)如果左子树大于右子树的话,就让他把下标移到右子树
2)判断这个值是否大于当前元素,存储起来的数,大于就替换
3.调整到大顶堆是让父子数的值大于或者等于左子树
/**
* //将一个数组(二叉树),调整成大顶堆
* 大顶堆的概念是:父节点必须大于或者等于子节点
*
* @param arr 待调整的数组
* @param i 表示非叶子节点在数组中的索引
* @param length 表示对多少个元素进行调整,length是在逐渐减少
*/
public static void adjustheap(int[] arr, int i, int length) {
int temp = arr[i];//先取出当前元素的值
//开始进行调整,使用顺序二叉树,左子节点进行 比较
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
//!!!注意 :k+1<length是关键代码,少了这个的话排序会出问题
if (k + 1 < length && arr[k] < arr[k + 1]) {//如果左子节点小于右子节点
k++;//把数组的下标移动到右子节点下
}
if (arr[k] > temp) {//如果子节点大于父节点的话,就要把字节点和父节点进行替换
arr[i] = arr[k];
i = k;
} else {
break;
}
//当for循环之后,已经把最大值放到了i里
arr[i] = temp;//现在的i已经不是一开始的i,已经变成了需要调整位置的下标
}
}
四、实现堆排序(大顶堆)
堆排序的思想就是:当调整成大顶堆之后,父节点一定大于或等于子节点,那么第一个数就是最大值,把开头的数和末尾的数进行替换。替换完成之后最后的数就是最大数,剔除最大数之后,在把剩余的数调整成大顶堆,再重复之前的操作,直到最后排序完成
/**
* 堆排序的方法
* 第一步:先把数组按照大顶堆或者小顶堆的顺序排列
* 第二步:排列完成之后把开头的数和末尾的数进行交换
* 第三步,打印结果
*
* @param arr
*/
public static void heapSort(int[] arr) {
System.out.println("堆排序!!!");
//循环开始,从最小的子树开始根据大顶堆升序或者小顶堆降序进行排序
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustheap(arr, i, arr.length);
}
//将开头的数与末尾的数进行交换
for (int j = arr.length - 1; j > 0; j--) {
//进行交换
int temp = 0;
temp = arr[j];//末尾的数
arr[j] = arr[0];//开头的数和末尾的数进行交换
arr[0] = temp;
adjustheap(arr, 0, j);//再次进行排序,把最大的值放到第一个
}
// System.out.println(Arrays.toString(arr));
}
五、完整的测试代码
public class HeapSort {
public static void main(String[] args) {
int[] arr = {4, 6, 8, 5, 9};
heapSort(arr);
int[] array = new int[8000000];
for (int i = 1; i < 8000000; i++) {
array[i] = (int) (Math.random() * 80000);
}
long time = new Date(System.currentTimeMillis()).getTime();
heapSort(array);
long time1 = new Date(System.currentTimeMillis()).getTime();
System.out.println("堆排序花费的时间是 " + (time1 - time) + " 毫秒");
}
/**
* 堆排序的方法
* 第一步:先把数组按照大顶堆或者小顶堆的顺序排列
* 第二步:排列完成之后把开头的数和末尾的数进行交换
* 第三步,打印结果
*
* @param arr
*/
public static void heapSort(int[] arr) {
System.out.println("堆排序!!!");
//循环开始,从最小的子树开始根据大顶堆升序或者小顶堆降序进行排序
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustheap(arr, i, arr.length);
}
//将开头的数与末尾的数进行交换
for (int j = arr.length - 1; j > 0; j--) {
//进行交换
int temp = 0;
temp = arr[j];//末尾的数
arr[j] = arr[0];//开头的数和末尾的数进行交换
arr[0] = temp;
adjustheap(arr, 0, j);//再次进行排序,把最大的值放到第一个
}
// System.out.println(Arrays.toString(arr));
}
/**
* //将一个数组(二叉树),调整成大顶堆
* 大顶堆的概念是:父节点必须大于或者等于子节点
*
* @param arr 待调整的数组
* @param i 表示非叶子节点在数组中的索引
* @param length 表示对多少个元素进行调整,length是在逐渐减少
*/
public static void adjustheap(int[] arr, int i, int length) {
int temp = arr[i];//先取出当前元素的值
//开始进行调整,使用顺序二叉树,左子节点进行 比较
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
//!!!注意 :k+1<length是关键代码,少了这个的话排序会出问题
if (k + 1 < length && arr[k] < arr[k + 1]) {//如果左子节点小于右子节点
k++;//把数组的下标移动到右子节点下
}
if (arr[k] > temp) {//如果子节点大于父节点的话,就要把字节点和父节点进行替换
arr[i] = arr[k];
i = k;
} else {
break;
}
//当for循环之后,已经把最大值放到了i里
arr[i] = temp;//现在的i已经不是一开始的i,已经变成了需要调整位置的下标
}
}
}