package algroithm;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author Snail
* @Describe 用于堆算法的测试
* @CreateTime 2019/7/25
*
*
* 堆中父子节点索引的关系:
* childIndex=parentIndex*2+1(左节点在数组中的索引)
* childIndex=parentIndex*2+2(右节点在数组中的索引)
*/
public class TestHeap {
public static void main(String[] args) {
//1. 将任意一个数组构建为小顶堆
int[] arr = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6};
buildHeap(arr);
System.out.println(Arrays.toString(arr)); //[1, 5, 2, 6, 7, 3, 8, 9, 10]
//2. 交换堆顶元素与末尾元素 + 调整堆结构:得到堆排序后的有序数组
for (int i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
downAdjust(arr, 0, i);
}
System.out.println(Arrays.toString(arr));//[10, 9, 8, 7, 6, 5, 3, 2, 1]
/**
*1中堆构建的时间复杂度为O(n),2中堆调整的时间复杂度为nlog(n),所以认为堆排序的时间复杂度为O(nlog(n))
*/
//加入一个元素到小顶堆中(加入元素到堆中,自能将新元素加在数组最后)
Scanner scanner = new Scanner(System.in);
int childNode = Integer.parseInt(scanner.nextLine());//0
int[] arrHeap = new int[]{1, 5, 2, 6, 7, 3, 8, 9, 10};
arrHeap = upAdjust(arrHeap, childNode);
System.out.println(Arrays.toString(arrHeap));//[0, 1, 2, 6, 5, 3, 8, 9, 10, 7]
//删除堆顶元素,堆中每次都只能删除第0个数据,并将最后一个元素放到数组的0位置
arrHeap = delNode(arrHeap);
System.out.println(Arrays.toString(arrHeap));//[1, 5, 2, 6, 7, 3, 8, 9, 10]
}
private static void swap(int[] arr, int i, int i1) {
int temp = arr[i];
arr[i] = arr[i1];
arr[i1] = temp;
}
/**
* 构建一个小顶堆(任何一个父节点的值,都小于等于它左右孩子节点的值)
*
* @param arr 待调整的堆
*/
public static void buildHeap(int[] arr) {
// 从最后一个非叶子节点开始到根节点,依次下沉调整
for (int i = arr.length / 2; i >= 0; i--) {
downAdjust(arr, i, arr.length);
}
}
/**
* 堆中某个元素的下沉调整
*
* @param arrHeap 待调整的堆
* @param parentIndex 下沉的节点
* @param length 堆数组的长度
*/
public static void downAdjust(int[] arrHeap, int parentIndex, int length) {
//保存父节点值,避免元素交换,并用于最后的赋值
int temp = arrHeap[parentIndex];
int childIndex = parentIndex * 2 + 1;
while (childIndex < length) {//表示节点还没下沉到数组的最后位置
//判断是否存在右节点,并找到两个孩子节点的最小值
if (childIndex + 1 < length && arrHeap[childIndex] > arrHeap[childIndex + 1]) {
childIndex++;
}
//如果父节点小于孩子节点的最小值,则证明他不需要下沉了
if (temp <= arrHeap[childIndex]) {
break;
}
//将孩子节点上浮到父节点位置
arrHeap[parentIndex] = arrHeap[childIndex];
parentIndex = childIndex;
childIndex = parentIndex * 2 + 1;
}
arrHeap[parentIndex] = temp;
}
/**
* 堆中元素的上浮调整,上浮最后一个元素
*
* @param arrHeap 待调整的堆
* @param childNode
*/
public static int[] upAdjust(int[] arrHeap, int childNode) {
//复制数组到新的空间
int childIndex = arrHeap.length;
int[] newHeap = new int[childIndex + 1];
System.arraycopy(arrHeap, 0, newHeap, 0, childIndex);
//上浮元素
newHeap[childIndex] = childNode;
int parentIndex = (childIndex - 1) / 2;
while (childIndex > 0 && childNode < newHeap[parentIndex]) {
//将parent节点替换到child节点
newHeap[childIndex] = newHeap[parentIndex];
childIndex = parentIndex;
//获取父节点的父节点
parentIndex = (parentIndex - 1) / 2;
}
newHeap[childIndex] = childNode;
return newHeap;
}
/**
* 删除小顶堆中堆顶
*
* @param arrHeap
* @return
*/
private static int[] delNode(int[] arrHeap) {
//构建新数组地址空间
int[] newHeap = new int[arrHeap.length - 1];
System.arraycopy(arrHeap, 0, newHeap, 0, arrHeap.length - 1);
newHeap[0] = arrHeap[arrHeap.length - 1];
downAdjust(newHeap, 0, newHeap.length);
return newHeap;
}
}
堆排序算法的时间复杂度可认为是O(nlog(n))
算法实现可参考:https://mp.weixin.qq.com/s/cq2EhVtOTzTVpNpLDXfeJg