天天看點

排序算法(冒泡、選擇、插入、希爾、歸并、快排、堆排序)

排序算法(冒泡、選擇、插入、希爾、歸并、快排、堆排序)
package Sort;

public class sort {
	// https://www.cnblogs.com/onepixel/articles/7674659.html
	public static void main(String[] args) {
		int[] arr = { 2, 6, 3, 5, 7, 3, 6, 8 };
		HeapSort(arr);
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
	}
	// 冒泡
	// 每次比較相鄰的元素,如果第一個比第二個大就交換他們兩個
	// 這樣交換到最後,最後的元素是最大的
	// 針對除了最後一個元素以外的所有元素重複以上步驟
	public static void BubbleSort(int[] arr) {
		int len = arr.length;
		for (int i = 0; i < len - 1; i++) {
			for (int j = 0; j < len - 1 - i; j++) {
				if (arr[j] > arr[j + 1]) {
					int temp = arr[j + 1];
					arr[j + 1] = arr[j];
					arr[j] = temp;
				}
			}
		}
	}

	// 選擇排序
	// 在未排序序列中找到最小的元素,放到排序序列的起始位置,
	// 然後再從剩餘未排序元素中繼續尋找最小的元素,放在已排序的末尾
	public static void SelectionSort(int[] arr) {
		int len = arr.length;
		int min = 0;
		for (int i = 0; i < len - 1; i++) {
			min = i;
			for (int j = i + 1; j < len; j++) {
				if (arr[j] < arr[min]) {
					min = j;
				}
			}
			if (min != i) {
				int temp = arr[i];
				arr[i] = arr[min];
				arr[min] = temp;
			}
		}
	}

	// 插入排序
	// 從第一個元素開始,該元素可以認為已經被排序
	// 取出下一個元素,在已經排序的元素序列中從後向前掃描
	// 找到他在已排序的序列中的位置
	public static void InsertSort(int[] arr) {
		int len = arr.length;
		for (int i = 1; i < len; i++) {
			for (int j = i; j > 0; j--) {
				if (arr[j] < arr[j - 1]) {
					int temp = arr[j];
					arr[j] = arr[j - 1];
					arr[j - 1] = temp;
				}
			}
		}
	}

	// 希爾排序
	// 插入排序的改進版,會優先比較距離較遠的元素
	public static void Shell(int[] arr) {
		int n = arr.length;
		int h = 1;
		while (h < n / 3) {
			// 1,4,13……
			h = h * 3 + 1;
		}
		while (h >= 1) {
			for (int i = h; i < n; i++) {
				for (int j = i; j >= h; j--) {
					if (arr[j] < arr[j - h]) {
						int temp = arr[j];
						arr[j] = arr[j - h];
						arr[j - h] = temp;
					}
				}
				h = h / 3;
			}
		}
	}

	// 歸并排序
	// 把長度為n的輸入序列分成兩個長度為n/2的子序列
	// 對這兩個子序列分别采用歸并排序
	// 将兩個排序好的子序列合并成一個最終的排序序列
	public static void MergeSort(int[] arr, int start, int end) {
		if (arr == null || start >= end) {
			return;
		}
		int middle = (start + end) / 2;
		// 遞歸
		MergeSort(arr, start, middle);
		MergeSort(arr, middle + 1, end);
		// 歸并
		Merge(arr, start, middle, end);
	}

	public static void Merge(int[] arr, int start, int mid, int end) {
		int[] array = new int[end + 1]; // 定義一個臨時數組,用來存儲排序後的結果
		int k = start; // 臨時數組的索引
		int i = start;
		int j = mid + 1;
		// 取出最小值放入臨時數組中
		while (i <= mid && j <= end) {
			array[k++] = arr[i] > arr[j] ? arr[j++] : arr[i++];
		}

		// 若還有段序列不為空,則将其加入臨時數組末尾
		while (i <= mid) {
			array[k++] = arr[i++];
		}
		while (j <= end) {
			array[k++] = arr[j++];
		}

		// 将臨時數組中的值copy到原數組中
		for (int m = start; m <= end; m++) {
			arr[m] = array[m];
		}

	}

	// 快速排序
	// 從數列中挑選一個數作為基準
	// 所有元素比基準小的放在基準前面,比基準大的放在基準後面,退出後,基準在中間位置
	// 遞歸
	public static void QuickSort(int[] a, int start, int end) {
		// 1,找到遞歸算法的出口
		if (start > end) {
			return;
		}
		// 2, 存
		int i = start;
		int j = end;
		// 3,key
		int key = a[start];
		// 4,完成一趟排序
		while (i < j) {
			// 4.1 ,從右往左找到第一個小于key的數
			while (i < j && a[j] > key) {
				j--;
			}
			// 4.2 從左往右找到第一個大于key的數
			while (i < j && a[i] <= key) {
				i++;
			}
			// 4.3 交換
			if (i < j) {
				int temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
		// 4.4,調整key的位置
		int temp = a[i];
		a[i] = a[start];
		a[start] = temp;
		// 5, 對key左邊的數快排
		QuickSort(a, start, i - 1);
		// 6, 對key右邊的數快排
		QuickSort(a, i + 1, end);
	}

	// 堆排序
	// 父節點的鍵值大于子節點
	// 建構大根堆:将array看成完全二叉樹的順序存儲結構
	private static int[] buildMaxHeap(int[] array) {
		// 從最後一個節點array.length-1的父節點(array.length-1-1)/2開始,直到根節點0,反複調整堆
		for (int i = (array.length - 2) / 2; i >= 0; i--) {
			adjustDownToUp(array, i, array.length);
		}
		return array;
	}

	// 将元素array[k]自下往上逐漸調整樹形結構
	private static void adjustDownToUp(int[] array, int k, int length) {
		int temp = array[k];
		for (int i = 2 * k + 1; i < length - 1; i = 2 * i + 1) { // i為初始化為節點k的左孩子,沿節點較大的子節點向下調整
			if (i< length && array[i] < array[i + 1]) { // 取節點較大的子節點的下标
				i++; // 如果節點的右孩子>左孩子,則取右孩子節點的下标
			}
			if (temp >= array[i]) { // 根節點 >=左右子女中關鍵字較大者,調整結束
				break;
			} else { // 根節點 <左右子女中關鍵字較大者
				array[k] = array[i]; // 将左右子結點中較大值array[i]調整到雙親節點上
				k = i; // 【關鍵】修改k值,以便繼續向下調整
			}
		}
		array[k] = temp; // 被調整的結點的值放人最終位置
	}

	// 堆排序
	public static void HeapSort(int[] array) {
		array = buildMaxHeap(array); // 初始建堆,array[0]為第一趟值最大的元素
		for (int i = array.length - 1; i >=1; i--) {
			int temp = array[0]; // 将堆頂元素和堆低元素交換,即得到目前最大元素正确的排序位置
			array[0] = array[i];
			array[i] = temp;
			adjustDownToUp(array, 0, i); // 整理,将剩餘的元素整理成堆
		}
	}


}
           

繼續閱讀