堆排序分析實現
阿新 • • 發佈:2019-02-20
演算法思想
若升序,建大堆,每次選擇堆頂元素即最大的數,和最後一位交換,再縮小堆的範圍(避免剛排好的最後一個位置被調回去),對剩下的進行向下調整(此時只有根節點不對,左右子樹都滿足大堆)。反覆進行直到堆的範圍為0.則資料就有序了。
程式碼實現思路
堆排序的實現首先是需要將陣列調整為一個大堆或者小堆,然後就是迴圈交換和調整堆的過程。因為在建堆和調整堆過程都用到了將陣列的某一部分調整為一個堆,所以抽出為一個adjustArray(int[] nums, int start, int end)函式。
時間複雜度
O(nlogn)。
建堆的時間複雜度近似為O(n*log n),每次選一個數後進行調整的複雜度也近似為O(n*log n),時間複雜度忽略係數,結果就近似為O(n*log n)。
空間複雜度
O(1)
穩定性
不穩定。
堆的調整時可能會打亂穩定性。
程式碼實現
package sort;
/**
* @作者:dhc
* @建立時間:8:28 2018/8/15
* @排序方法:堆排序
* @時間複雜度:O(nlogn)。建堆的時間複雜度近似為O(n*log n),每次選一個數後進行調整的複雜度也近似為O(n*log n),時間複雜度忽略係數,結果就近似為O(n*log n).
* @空間複雜度:O(1)
* @穩定性:不穩定
*/
public class HeapSort {
//堆排序
public static void heapSort (int[] nums){
heapArray(nums);
int tem;
for(int i = nums.length - 1;i > 0;i--){
tem = nums[0];
nums[0] = nums[i];
nums[i] = tem;
adjustArray(nums,0,i-1);
}
}
//堆化陣列
public static void heapArray(int[] nums){
for (int i = nums.length / 2; i >= 0; i--) {
adjustArray(nums,i,nums.length);
}
}
//對某個節點進行一次從上到下的調整(建小堆的調整)
public static void adjustArray1(int[] nums, int start, int end){
int min;
int k;
for (int i = start; i < end;) {
if(2*i+2<=end){
//這裡是和左右子節點比較並的較小者交換,後面得到的是小堆,如果要大堆,則需要和比較後的較大者交換
min = nums[2*i+1] > nums[2*i+2] ? nums[2*i+2] : nums[2*i+1];
k = nums[2*i+1] > nums[2*i+2] ? 2*i+2 : 2*i+1;
if(nums[i] > min){
nums[k] = nums[i];
nums[i] = min;
i = k;
}else{
break;
}
}else{
break;
}
}
}
//建大堆的調整
public static void adjustArray(int[] nums, int start, int end){
int max;
int k;
for (int i = start; i < end;) {
if(2*i+2<=end){
max = nums[2*i+1] < nums[2*i+2] ? nums[2*i+2] : nums[2*i+1];
k = nums[2*i+1] < nums[2*i+2] ? 2*i+2 : 2*i+1;
if(nums[i] < max){
nums[k] = nums[i];
nums[i] = max;
i = k;
}else{
break;
}
}else{
break;
}
}
}
public static void main(String[] args) {
int[] nums = new int[]{1,0,5,3,7,9,2,4,5};
heapSort(nums);
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i]+" ");
}
}
}