堆排序:
堆排序时间复杂度是O(NlogN)
空间复杂度如果不用递归的话可以达到O(1),在数组上原地排序
这里给出堆排序代码
注意此处在筛操作的时候sift(Object[] a, int n, int i),中间的参数n是代表这时候数组的总大小。因为在建完堆后,数组从后往前会一轮一轮的有序,n会渐渐减小。在无序数组中找最小的k个数的代码中就不需要记录这个值,在这代码中,需要建大根堆,用数组中的其他数跟大根堆堆顶比较。
筛操作也就是sift()方法,它代表,在建好的二叉堆上如果堆顶换了一个值,通过筛操作使得该数组又符合二叉堆的条件。那为什么建堆的时候也是用这个方法呢,因为这里是从底向上建堆,每次经过父节点时,都能保证它的左孩子和右孩子是二叉堆。
这里建堆的复杂度就是O(N),而不是我们想象中的O(NlogN)。
建堆过程和时间复杂度证明如下
但是后面排序,即把堆顶放到数组后面的过程,在进行筛操作,时间复杂度就变成O(NlogN)了。
public class Solution {
public static void main(String[] args) {
Integer[] a = new Integer[]{3,4,2,6,5,7,9,1,8};
heapSort(a, 9);
System.out.println(Arrays.toString(a));
//buildHeap(a);
return;
}
public static void heapSort(Object[] a, int n) {
Object x;
for (int i = n / 2 - 1; i >= 0; i--) {
sift(a, n, i);
}
for (int i = 1; i < n; i++) {
x = a[0];
a[0] = a[n-i];
a[n-i] = x;
sift(a, n-i, 0);
}
return;
}
public static void sift(Object[] a, int n, int i){
int j = 2*i+1;
while (j <= n-1){
if (j<n-1 && ((Comparable)a[j]).compareTo((Comparable)a[j+1]) <0){
j++;
}
if (((Comparable)a[i]).compareTo((Comparable)a[j]) <0){
swap(a, i, j);
i = j;
j = 2*i+1;
}
else {
break;
}
}
}
public static void swap(Object[] a, int i, int j){
Object tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
【无序数组中找到最小的k个数】
假设数组长度是N
下面代码的时间复杂度O(NlogK)
还有一种方法可以做到时间复杂度O(N),利用快速排序的原理。
public class Main {
public static void main(String[] args) {
int[] arr = { 6, 9, 1, 3, 1, 2, 2, 5, 6, 1, 3, 5, 9, 7, 2, 5, 6, 1, 9 };
int k = 10;
System.out.println(Arrays.toString(getMinKNumsByHeap(arr, k)));
}
//自己建立大根堆排序
public static int[] getMinKNumsByHeap(int[] arr, int k){
int[] heap = new int[k];
for (int i = 0; i < k; i++) {
heap[i] = arr[i];
}
for (int i = k/2 -1; i >= 0 ; i--) {
seaf(heap, i);
}
//k+1..,N个值一一放进去比对
for (int i = k; i < arr.length; i++) {
if (arr[i] < heap[0]){
heap[0] = arr[i];
seaf(heap, 0);
}
}
return heap;
}
//筛选堆
public static void seaf(int[] arr, int i){
int father = i;
int index = 2 * i + 1;
while (index < arr.length){
if (index < arr.length -1){
if (arr[index+1] > arr[index]){
index = index +1;
}
}
if (arr[index] > arr[father]){
int tmp = arr[index];
arr[index] = arr[father];
arr[father] = tmp;
father = index;
index = 2* index + 1;
}
else {
break;
}
}
}
}