詳解堆排序 附程式碼 無序陣列中找到最小的k個數
阿新 • • 發佈:2019-02-18
堆排序:
堆排序時間複雜度是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;
}
}
}
}