堆排序Heap Sort
时间复杂度: O(nlogn)
在insert()操作和extractMax()操作中,时间复杂度都是logn级别的,因为shiftUp()和shiftDown()操作中,不管是将元素从下到上,从上到下一层层找到合适的位置都是和层序相关的。
二叉堆 Binary Heap:堆总是一颗完全二叉树
最大堆(大顶堆): 堆中每个节点的值总是不大于其父节点的值。
用数组存储二叉堆:
索引从1开始时,某个节点i的父节点为parent(i)=i/2,其左孩子为left child(i)=2i,其右孩子为right child(i)=2i+1.
大顶堆中插入元素:Shift Up
大顶堆我们通过数组来存储,向大顶堆中添加一个元素相当于向数组的末尾添加一个元素,count++。此时的堆不满足大顶堆的定义(52>16),需要进行Shift Up操作将其转化为一个大顶堆。
我们需要将新加入的元素调整到合适的位置,使整棵二叉树符合大顶堆的定义。具体步骤为:新加入的元素与他的父亲节点比,如果父节点比新加入的元素小,则交换两者的位置,此时52和16进行交换。
此时52可能还会比他此时的父亲节点大,两者进行比较,此时52>41,两者进行位置交换。
此时52可能还会比他此时的父亲节点大,两者进行比较,此时52<62,两者不用进行位置交换。
大顶堆中取出最大元素:Shift Down
在大顶堆中取出一个元素只能取出最大值。当取出堆顶元素(数组中第一个元素)时,将数组中最后一个元素移到堆顶位置,count–,此时堆依然是一课完全二叉树,但不是大顶堆,需要进行Shift Down操作将其转化为一个大顶堆。
将根节点元素的位置一步一步的往下移动,直到找到合适的位置。
左右两个孩子进行比较,谁大就和谁换。
继续左右两个孩子进行比较,谁大就和谁换。此时16只有左孩子,就拿他和左孩子进行比较,此时16>15,不需要进行交换,同时Shift Down也就结束了。
package sort.heap;
/**
* 大顶堆
*
* @author cuiyongling
* @since V1.0.0
* 2020-04-14 12:55
*/
public class MaxHeap<E extends Comparable<E>> {
private Object[] data;
private int count;
private int capacity;
public MaxHeap(int capacity){
data = new Object[capacity+1];
count = 0;
this.capacity = capacity;
}
public int size(){
return count;
}
public boolean isEmpty(){
return count ==0;
}
public void insert(E e){
//索引从1开始
if(count+1 <= capacity){
data[count+1] = e;
count ++;
shiftUp(count);
}else{
throw new IllegalArgumentException("has no space to insert a new number");
}
}
private void shiftUp(int k){
while(k > 1 && ((E)data[k/2]).compareTo((E)data[k]) <0){
//进行位置交换 优化:每次进行比较赋值操作,而不是交换操作,就像插入排序中的优化,找到最终的位置进行插入
E temp = (E)data[k/2];
data[k/2]= data[k];
data[k] = temp;
//维护k
k = k/2;
}
}
public E extractMax(){
if(count >0){
E e = (E)data[1];
E temp = (E)data[count];
data[count] = data[1];
data[1] = temp;
count --;
shiftDown(1);
return e;
}else{
throw new IllegalArgumentException("has no item in array");
}
}
private void shiftDown(int k){
//当其有孩子,只要他有左孩子
while(2*k <=count){
//在此轮循环中,data[k]和data[j]交换位置
int j = 2*k;
//判断是否有右孩子
if(j+1 <=count && ((E)data[j+1]).compareTo((E)data[j]) >0){
j= j+1;
}
if(((E)data[k]).compareTo((E)data[j]) >=0){
break;
}
//进行交换
E temp = (E)data[k];
data[k] = data[j];
data[j] = temp;
k = j;
}
}
}
package sort;
import sort.heap.MaxHeap;
/**
* 堆排序
*
* @author cuiyongling
* @since V1.0.0
* 2020-04-14 15:55
*/
public class HeapSort<E extends Comparable<E>> {
public void heapSort(E[] arr, int n){
MaxHeap<E> maxHeap = new MaxHeap<>(n);
for(int i=0; i<n;i++){
maxHeap.insert(arr[i]);
}
for(int i =n-1; i>=0;i--){
arr[i] = maxHeap.extractMax();
}
for(int i =0;i<n;i++){
System.out.print(arr[i]+" ");
}
}
public static void main(String[] args){
HeapSort<Integer> heapSort = new HeapSort<>();
int n=10;
Integer[] arr = new Integer[n];
Random random = new Random();
for(int i=0; i<n;i++){
arr[i] = random.nextInt(100);
}
heapSort.heapSort(arr,n);
}
}