堆排序:就是一个不断调整最大堆/最小堆的过程。
最大值元素在堆顶,每拿出一个堆顶,就调整堆一次,时间复杂度是:n*logn,一次调整堆的时间复杂度是logn
/*
* 堆排序
*/
public class HeapSort {
@Test
public void heapC(){
int[] arr = new int[]{1,2,3,4,5,6,1}; //arr下标从0~n-1
// 根节点最后一个父节点的序号为,(arr.length-1)/2,向自己及自己的子树调整出最大根,
for(int i=(arr.length-1)/2;i>=0;i--){
//向自己及自己的子树调整出最大根
adjust(arr,i);
}
//显示结果
for(int i=0;i<arr.length;i++){
System.out.println(" "+arr[i]);
}
}
//k是当前待调整元素的下标
public static void adjust(int arr[],int k){
int temp = arr[k];
// 从k的子树下标开始比较,找到比自己值大的子树下标,就交换,然后交换的位置继续比较其子树
// 因为下标是从0开始的,所以其左子树和右子树下标是,2*(k+1)i-1和2*(k+1) i=2*(i+1)-1 就是找其左子树
for(int i = 2*(k+1)-1;i<arr.length;i=2*(i+1)-1){
//先比较,如果右节点存在,且右节点大于左节点,就用右节点去交换
if(i+1<arr.length && arr[i+1]>arr[i]){
//与右节点比较,且交换,k值更新,i值更新
if(temp<arr[i+1]){
arr[k] = arr[i+1];
arr[i+1] = temp;
k=i+1;
i++;
}else { //大于最大的子节点,就不需要再调整
break;
}
//左节点大于右节点,
}else if(temp<arr[i]){
arr[k] = arr[i];
arr[i] = temp;
k=i;
}
else{
break;
}
}
}
}
package algothrim.sort;
import org.junit.Test;
/*
* 堆排序
*/
public class HeapSort {
@Test
public void heapC(){
int[] arr = new int[]{0,1,2,3,4,5,6,1}; //arr有效数据下标从1~n-1
// 根节点最后一个父节点的序号为,(arr.length-1)/2,向自己及自己的子树调整出最大根,
int len = arr.length-2; //数组的长度
//初始建堆
for(int i=len/2; i>=1; i--){
//向自己及自己的子树调整出最大根
adjustDown(arr,i,len);
}
//堆排序: 这是一个大根堆,每出一个堆顶就与该堆的最后一个元素交换,所以最后是从小到大的顺序输出
heapSort(arr,arr.length-2);
//插入之前结果
for(int i=1;i<arr.length;i++){
System.out.print(" "+arr[i]);
}
System.out.println();
//插入一个节点
adjustUp(arr,arr.length-1);
插入之后显示结果
for(int i=1;i<arr.length;i++){
System.out.print(" "+arr[i]);
}
}
//k是当前待调整元素的下标,len是最后一个元素的下标+1
public static void adjustDown(int arr[],int k,int len){
arr[0] = arr[k];
for(int i=2*k;i<=len;i*=2) {
if (i < len && arr[i] < arr[i + 1])
i++;
if (arr[0] >= arr[i])
break;
else {
arr[k] = arr[i];
k = i;
}
}
arr[k] = arr[0]; //被筛选节点的值放入最终位置
}
//堆排序:就是一个删除堆顶元素的过程,删除堆顶元素时,先将堆的最后一个元素与堆顶元素交换,然后进行向下调整
//arr的有效数据是1~n-1
public void heapSort(int arr[],int len){
for (int i = len;i>0;i--){
swap(arr,i,1); //输出堆顶元素,和堆底元素交换
adjustDown(arr,1,i-1);
}
}
public void swap(int a[],int i,int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//插入堆顶元素,将元素进行向上调整
public void adjustUp(int a[],int k){
a[0] = a[k];
int i=k/2;
while(i>0 && a[i]<a[0]){
a[k] = a[i];
k = i;
i=k/2; //继续向父节点比较
}
a[k] = a[0]; //将a[0]放到最终的位置
}
}