1. 程式人生 > 其它 >Web自動化測試框架實戰-基於unittest

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值放到調整後的位置
	}
	
}