Web自動化測試框架實戰-基於unittest
堆排序基本介紹
1) 堆排序是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序,它的最壞,最好,平均時間復
雜度均為 O(nlogn),它也是不穩定排序。
2) 堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆, 注意 : 沒有
要求結點的左孩子的值和右孩子的值的大小關係。
3) 每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆
4) 大頂堆舉例說明
5) 小頂堆舉例說明
6) 一般升序採用大頂堆,降序採用小頂堆
堆排序基本思想
堆排序的基本思想是:
1) 將待排序序列構造成一個大頂堆
2) 此時,整個序列的最大值就是堆頂的根節點。
3) 將其與末尾元素進行交換,此時末尾就為最大值。
4) 然後將剩餘 n-1 個元素重新構造成一個堆,這樣會得到 n 個元素的次小值。如此反覆執行,便能得到一個有序
序列了。
可以看到在構建大頂堆的過程中,元素的個數逐漸減少,最後就得到一個有序序列了.
堆排序步驟圖解說明
要求:給你一個數組 {4,6,8,5,9} , 要求使用堆排序法,將陣列升序排序。
步驟一 構造初始堆。將給定無序序列構造成一個大頂堆(一般升序採用大頂堆,降序採用小頂堆)。
原始的陣列 [4, 6, 8, 5, 9]
2) .此時我們從最後一個非葉子結點開始(葉結點自然不用調整,第一個非葉子結點
arr.length/2-1=5/2-1=1,也就是下面的 6 結點),從左至右,從下至上進行調整。
3) .找到第二個非葉節點 4,由於[4,9,8]中 9 元素最大,4 和 9 交換。
4) 這時,交換導致了子根[4,5,6]結構混亂,繼續調整,[4,5,6]中 6 最大,交換 4 和 6。
此時,我們就將一個無序序列構造成了一個大頂堆。
步驟二 將堆頂元素與末尾元素進行交換,使末尾元素最大。然後繼續調整堆,再將堆頂元素與末尾元素交換,
得到第二大元素。如此反覆進行交換、重建、交換。
1) .將堆頂元素 9 和末尾元素 4 進行交換
2) .重新調整結構,使其繼續滿足堆定義
3) .再將堆頂元素 8 與末尾元素 5 進行交換,得到第二大元素 8.
4) 後續過程,繼續進行調整,交換,如此反覆進行,最終使得整個序列有序
再簡單總結下堆排序的基本思路:
1).將無序序列構建成一個堆,根據升序降序需求選擇大頂堆或小頂堆;
2).將堆頂元素與末尾元素交換,將最大元素"沉"到陣列末端;
3).重新調整結構,使其滿足堆定義,然後繼續交換堆頂元素與當前末尾元素,反覆執行調整+交換步驟,
直到整個序列有序。
程式碼實現
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class HeapSort {
public static void main(String[] args) {
//要求將陣列進行升序排序
//int arr[] = {4, 6, 8, 5, 9};
// 建立要給80000個的隨機的陣列
int[] arr = new int[8000000];
for (int i = 0; i < 8000000; i++) {
arr[i] = (int) (Math.random() * 8000000); // 生成一個[0, 8000000) 數
}
System.out.println("排序前");
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("排序前的時間是=" + date1Str);
heapSort(arr);
Date data2 = new Date();
String date2Str = simpleDateFormat.format(data2);
System.out.println("排序前的時間是=" + date2Str);
//System.out.println("排序後=" + Arrays.toString(arr));
}
//編寫一個堆排序的方法
public static void heapSort(int arr[]) {
int temp = 0;
System.out.println("堆排序!!");
// //分步完成
// adjustHeap(arr, 1, arr.length);
// System.out.println("第一次" + Arrays.toString(arr)); // 4, 9, 8, 5, 6
//
// adjustHeap(arr, 0, arr.length);
// System.out.println("第2次" + Arrays.toString(arr)); // 9,6,8,5,4
//完成我們最終程式碼
//將無序序列構建成一個堆,根據升序降序需求選擇大頂堆或小頂堆
for(int i = arr.length / 2 -1; i >=0; i--) {
adjustHeap(arr, i, arr.length);
}
/*
* 2).將堆頂元素與末尾元素交換,將最大元素"沉"到陣列末端;
3).重新調整結構,使其滿足堆定義,然後繼續交換堆頂元素與當前末尾元素,反覆執行調整+交換步驟,直到整個序列有序。
*/
for(int j = arr.length-1;j >0; j--) {
//交換
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, j);
}
//System.out.println("陣列=" + Arrays.toString(arr));
}
//將一個數組(二叉樹), 調整成一個大頂堆
/**
* 功能: 完成 將 以 i 對應的非葉子結點的樹調整成大頂堆
* 舉例 int arr[] = {4, 6, 8, 5, 9}; => i = 1 => adjustHeap => 得到 {4, 9, 8, 5, 6}
* 如果我們再次呼叫 adjustHeap 傳入的是 i = 0 => 得到 {4, 9, 8, 5, 6} => {9,6,8,5, 4}
* @param arr 待調整的陣列
* @param i 表示非葉子結點在陣列中索引
* @param lenght 表示對多少個元素繼續調整, length 是在逐漸的減少
*/
public static void adjustHeap(int arr[], int i, int lenght) {
int temp = arr[i];//先取出當前元素的值,儲存在臨時變數
//開始調整
//說明
//1. k = i * 2 + 1 k 是 i結點的左子結點
for(int k = i * 2 + 1; k < lenght; k = k * 2 + 1) {
if(k+1 < lenght && arr[k] < arr[k+1]) { //說明左子結點的值小於右子結點的值
k++; // k 指向右子結點
}
if(arr[k] > temp) { //如果子結點大於父結點
arr[i] = arr[k]; //把較大的值賦給當前結點
i = k; //!!! i 指向 k,繼續迴圈比較
} else {
break;//!
}
}
//當for 迴圈結束後,我們已經將以i 為父結點的樹的最大值,放在了 最頂(區域性)
arr[i] = temp;//將temp值放到調整後的位置
}
}