自己的版本:
主要是利用了以下规则:
对于一个完全二叉树,以下公式成立:
Node n的左子节点 = 2n+1
Node n的右子节点= 2n + 2
长度为length的树,最后一个非叶子节点的节点编号是:length/2-1 (推算方法: 假设n是最后一个非叶子节点:
1) n只有一个左子节点, 2n+1 = length -1 => n = length/2 -1,
2)n 左右子节点都有, 2n + 2 = length -1 => n = lenth/2 -3/2 = length/2 -1
具体过程,可以参考如下文档:
https://www.cnblogs.com/chengxiao/p/6129630.html
package indi.tom.dataStructure.tree;
import org.junit.Test;
import java.util.Arrays;
/**
* @Author Tom
* @Date 2020/12/16 8:43
* @Version 1.0
* @Description
*/
public class HeapSortTest01 {
@Test
public void test(){
int[] array = {9,5,3,6,7,0,1,2};
heapSort(array);
System.out.println(Arrays.toString(array));
}
private void heapSort(int[] array){
//construct a initial max heap
//adjust from the last non-leaf node to the first non-leaf node
int length = array.length;
//从最后一个元素开始调整,这样可以,但不太好
//for (int i = 2*(length -1)/2; i >= 0 ; i--) {
//直接从最后一个非叶子节点开始调整,这样更好一些
for (int i = 2*(length -1)/2; i >= 0 ; i--) {
adjust(array, i, length);
}
//swap first and last element in the max heap, remove the last element
//then adjust again.
while(length > 1){
swap(array, 0, length -1);
adjust(array, 0, length -1);
length--;
}
}
/**
* Adjust a array/tree according to the given first non-leaf element index
* and the array/tree length that participates.
*
* @param array original array/tree
* @param index the non-leaf element index to start with
* @param length length of the array to be adjusted
*/
private void adjust(int[] array, int index, int length){
if(2*index + 1 >= length) return;
int max = 0;
if((2*index + 2) < length ){
max = array[2*index + 1] < array[2*index +2]? 2*index + 2:2*index + 1;
}else{
max = 2*index + 1;
}
if(array[index] < array[max]){
swap(array, index, max);
}else{
return;
}
adjust(array, max, length);
}
/**
*
* @param array
* @param i
* @param j
*/
private void swap(int[] array, int i, int j){
if(i > array.length - 1 || j > array.length -1) throw new IndexOutOfBoundsException();
int temp =array[i];
array[i] = array[j];
array[j] = temp;
}
}
教材版本:
/**
* 堆排序演示
*
* @author Lvan
*/
public class HeapSort {
public static void main(String[] args) {
// int[] arr = {5, 1, 7, 3, 1, 6, 9, 4};
int[] arr = {16, 7, 3, 20, 17, 8};
heapSort(arr);
for (int i : arr) {
System.out.print(i + " ");
}
}
/**
* 创建堆,
* @param arr 待排序列
*/
private static void heapSort(int[] arr) {
//创建堆
for (int i = (arr.length - 1) / 2; i >= 0; i--) {
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr, i, arr.length);
}
//调整堆结构+交换堆顶元素与末尾元素
for (int i = arr.length - 1; i > 0; i--) {
//将堆顶元素与末尾元素进行交换
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
//重新对堆进行调整
adjustHeap(arr, 0, i);
}
}
/**
* 调整堆
* @param arr 待排序列
* @param parent 父节点
* @param length 待排序列尾元素索引
*/
private static void adjustHeap(int[] arr, int parent, int length) {
//将temp作为父节点
int temp = arr[parent];
//左孩子
int lChild = 2 * parent + 1;
while (lChild < length) {
//右孩子
int rChild = lChild + 1;
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (rChild < length && arr[lChild] < arr[rChild]) {
lChild++;
}
// 如果父结点的值已经大于孩子结点的值,则直接结束
if (temp >= arr[lChild]) {
break;
}
// 把孩子结点的值赋给父结点
arr[parent] = arr[lChild];
//选取孩子结点的左孩子结点,继续向下筛选
parent = lChild;
lChild = 2 * lChild + 1;
}
arr[parent] = temp;
}
}