堆排序思路:
堆排序可以算是直接选择排序的一种优化的算法,采用了一种独有的堆数据结构对元素进行存储。然后通过这种数据结构的特点不断交换根节点元素与最后一个元素在对剩下的节点进行堆数据结构的重新构建。
堆数据结构:
类似于二叉堆的一种数据结构,把元素存储到数组当中以一种完全二叉树的形式进行存储,每个索引为N的父节点N*2为其左孩子N*2+1为其右孩子。并且父节点的值要大于左孩子以及右孩子。
堆数据结构的好处:
这种数据结构就把元素变成了根节点从上到下的有顺序的排列,这样根节点一直是当前堆数据中的最大值。方便了我们的操作并且减少了比较的次数。
堆排序的实现步骤:
- 对给定任意数组进行堆结构的建立
- 把根节点与最后一个节点进行交换,之后在对除最后节点外的所有节点进堆结构的建立
- 不断循环操作步骤2,最后得到由小到大的有规律的数组
用到的主要方法:
- heapSort (int[] array):对当前数组进行堆排序,里面调用了buildMaxHeap(array);方法 初始化堆结构,之后不断交换根元素与最后一个元素在对剩下元素调用maxHeap(array,i,0);
- buildMaxHeap(int[] array): 建立堆结构,从当前数组的中间部分开始建立因为没必要对叶子结点进行建立因为叶子结点没有左右孩子。
- maxHeap(int[] array,int heapSize,int index): 这是主要的方法,对给定的数组进行堆结构的建立,里面有许多具体的判断 可以看代码注释。
堆排序的时间复杂度:
O(NlogN); 他的比较次数远远小于直接选择排序,因为每次堆排序后比较的只是某一个子树中的元素。
代码:
package 堆排序;
public class HeapSort {
//堆排序的方法
public static void heapSort(int[] array){
//对传入的数组进行一个堆结构的初始化
buildMaxHeap(array);
//对这个堆进行堆排序,把根元素与最后一个元素进行交换
//之后在对除根元素外的所有元素进行堆数据结构的调整
for(int i = array.length-1;i>=1;i--){
array[i] = array[i]^array[0];
array[0] = array[i]^array[0];
array[i] = array[i]^array[0];
maxHeap(array,i,0);
}
}
public static void buildMaxHeap(int[] array){
//从堆数组中间进行建立
int half = array.length/2;
for(int i=half;i>=0;i--){
//调用建立堆结构的方法对其进行堆结构的建立
maxHeap(array,array.length,i);
}
}
//构建大根堆
public static void maxHeap(int[] array,int heapSize,int index){
//左右孩子 及最大元素索引
int left = index*2+1;
int right = index*2+2;
int largest = index;
//如果左孩子大于根节点 并且左孩子小于堆长度 则使最大索引等于左孩子
if(left<heapSize && array[left]>array[index]){
largest = left;
}
//如果右孩子大于最大索引节点 并且右孩子小于堆长度 则使最大索引等于右孩子
if(right<heapSize && array[right]>array[largest]){
largest = right;
}
//假如当前根节点不是最大的索引
if(index != largest){
//则让根节点与最大的索引元素进行交换
array[largest] = array[largest]^array[index];
array[index] = array[largest]^array[index];
array[largest] = array[largest]^array[index];
//然后在对最大索引处 的子树递归进行构建大根堆
maxHeap(array,heapSize,largest);
}
}
public static void main(String[] args) {
int[] array = {87,65,67,85,26,41,16,73,438,95,73,51,0};
HeapSort.heapSort(array);
for(int i =0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
}