堆排序
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
用简单的公式来描述一下就是:
大顶堆:arr[i]>=arr[2i+1] && arr[i]>=arr[2i+2]
小顶堆:arr[i]<=arr[2i+1] && arr[i]<=arr[2i+2]
思路(大顶堆):
- 将给定的待排序序列(R1,R2,...,Rn)构建成大顶堆,此堆为初始的无序区。
- 将堆顶元素R[1]与无序区的最后一个元素R[n]交换,此时得到新的无序区(R1,R2,...,Rn-1)和新的有序区(Rn)。
- 由于交换后新的堆顶R[1]可能违反大顶堆的性质,因此需要对当前无序区(R1,R2,...,Rn-1)调整为新的大顶堆,然后再次将RR[1]与无序区的最后一个元素R[n-1]交换,得到新的无序区(R1,R2,...,Rn-2)和新的有序区(Rn-1,Rn)。
- 不断重复此过程直到无序区还剩一个元素,则整个过程完成。
package 堆排序;
import java.util.Arrays;
public class Main{ public static void main(String[] args) { //定义一个数组 int[] arr = {2,34,54,65,1,3,3,34,23};
//调用方法,堆排序 heapSort(arr);
//打印结果 System.out.println(Arrays.toString(arr)); }
//堆排序入口方法 private static void heapSort(int[] arr) { //将数组初始化为最大堆 for(int i=arr.length/2-1;i>=0;i--){ adjust(arr,i,arr.length-1);//调用方法,调整最大堆 }
//j为无序数组最后一个元素的角标位置,从arr.length-1开始,到无序数组只剩一个元素 for(int j=arr.length-1;j>0;j--){ //将最大堆的第一个元素和最后一个元素交换 int tmp = arr[0]; arr[0] = arr[j]; arr[j] = tmp; //重新调整最大堆 adjust(arr,0,j-1); } }
//调整最大堆 //arr:待排序数组 i:要调整堆的堆顶元素角标 j:无序数组最后一个元素的角标 private static void adjust(int[] arr, int i, int j) { for(int k=2*i+1;k<=j;k=2*k+1){//k为左子节点的角标 //找左、右子节点中的最大值 if(k<j&&arr[k]<arr[k+1]){ k++; } //如果左、右子节点中的最大值大于父节点,交换位置 if(arr[k]>arr[i]){ int t = arr[k]; arr[k] = arr[i]; arr[i] = t; i = k;//重新调整堆顶元素角标位置 }else{ break; } } } } |