package ds;
/*
* author : codinglion
* contact: chenyakun@foxmail.com
*/
import java.util.Random;
publicclass Sorts {
// 冒泡排序
// 小數往上冒
public static int[] BubbleSort(int[] disOrderArray) {
int temp;
// 第一層循環:表明比較的次數, 比如 length 個元素,比較次數為 length-1 次(肯定不需和自己比)
for (int i = 0; i < disOrderArray.length - 1; i++) {
// 把最小的數交換着"冒泡"的相對的最上邊,一次冒上來的是最小的,其次是第二小的.
// length-1: 取數據最后一個數下標
// j>i 從后往前的下標一定大於從前往后的下標,否則越界了
for (int j = disOrderArray.length - 1; j > i; j--) {
if (disOrderArray[j] < disOrderArray[j - 1]) {
temp = disOrderArray[j];
disOrderArray[j] = disOrderArray[j - 1];
disOrderArray[j - 1] = temp;
}
}
}
// for (int element : disOrderArray) {
//
// System.out.print(element + " ");
// }
return disOrderArray;
}
/*
*
* 快速排序
*
* 思想:
* 通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,
* 則可以分別對這兩部分記錄繼續進行排序,已達到整個序列有序的目的
*
* 本質就是,找一個基位(樞軸,分水嶺,作用是左邊的都比它小,右邊的都比它大.可隨機,取名base
* 首先從序列最右邊開始找比base小的
* ,如果小,換位置,從而base移到剛才右邊(比較時比base小)的位置(記為臨時的high位),這樣base右邊的都比base大
* 然后,從序列的最左邊開始找比base大的
* ,如果大,換位置,從而base移動到剛才左邊(比較時比base大)的位置(記為臨時的low位),這樣base左邊的都比base小
*
* 循環以上兩步,直到 low == heigh, 這使才真正的找到了樞軸,分水嶺. 返回這個位置,分水嶺左邊和右邊的序列,分別再來遞歸
*/
public static int[] quickSort(int[] arr, int low, int heigh) {
if (low < heigh) {
int division = partition(arr, low, heigh);
quickSort(arr, low, division - 1);
quickSort(arr, division + 1, heigh);
}
return arr;
}
// 分水嶺,基位,左邊的都比這個位置小,右邊的都大
public static int partition(int[] arr, int low, int heigh) {
int base = arr[low]; //用子表的第一個記錄做樞軸(分水嶺)記錄
while (low < heigh) { //從表的兩端交替向中間掃描
while (low < heigh && arr[heigh] >= base) {
heigh--;
}
// base 賦值給 當前 heigh 位,base 挪到(互換)到了這里,heigh位右邊的都比base大
swap(arr, heigh, low);
while (low < heigh && arr[low] <= base) {
low++;
}
// 遇到左邊比base值大的了,換位置
swap(arr, heigh, low);
}
// now low = heigh;
return low;
}
private static void swap(int[] arr, int a, int b) {
int temp;
temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
/*
*
* 直接選擇排序
*/
public static int[] selectionSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int miniPos = miniPos(arr, i, arr.length);
if (arr[i] > arr[miniPos]) {
swap(arr, i, miniPos);
}
}
returnnull;
}
// 返回最小的時序列中的哪一位
public static int miniPos(int[] arr, int from, int end) {
int miniPost = from;
for (int i = from + 1; i < end; i++) {
if (arr[i] < arr[miniPost]) {
miniPost = i;
}
}
return miniPost;
}
/*
* heap sort 堆排序
*/
// 本質就是先構造一個大頂堆,parent比children大,root節點就是最大的節點
// 把最大的節點(root)與尾節點(最后一個節點,比較小)位置互換
// 剩下最后的尾節點,現在最大,其余的,從第一個元素開始到尾節點前一位,構造大頂堆
// 遞歸
public static int[] heapSort(int[] arr) {
int i;
// 將arr構成一個大頂堆
// 從 0 到 arr.length/2 ,這些都是有孩子的節點
// 沒孩子的節點構造大頂堆就無意義了
for (i = arr.length / 2; i >= 0; i--) {
heapAdjust(arr, i, arr.length - 1);
}
for (i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
// 將arr[0...i-1] 重新構造成一個大頂堆
heapAdjust(arr, 0, i - 1);
}
return arr;
}
private static void heapAdjust(int[] arr, int s, int m) {
int temp, j;
temp = arr[s]; // 指向臨時(相對與root節點)的根節點
for (j = 2 * s; j <= m; j *= 2) {
// 如果右節點比左節點大,當前節點移到右節點
if (j < m && arr[j] < arr[j + 1]) {
// 指向右節點
j++;
}
// 當前的父節點大於現在指向的節點
// 不需要做任何處理
if (temp >= arr[j]) {
break;
}
// 當前的父節點小於其下的子節點
// 換位置,把這個子節點替換到父節點
// 當前這個位置,如果是葉子節點,則它應該是最小的(相對於它的祖先們)
// 這個方法目的就是交換parent與children的值,構造大根堆
// 執行到這里表明當前節點的父節點(臨時根節點小於當前的節點),
// 把當前節點移到上面,換位置
// arr[s]被覆蓋無所謂,因為temp記了這個值(原來的根節點(相對的parent))
arr[s] = arr[j];
// 現在把當前的這個元素,看做是臨時的parent節點
// 為了找到此時這個元素的孩子節點,看看是否有比當前這個值還大的
// 最后s指向 當前遍歷到的這個元素
s = j;
}
arr[s] = temp;
}
/*
* 插入排序
* 思想: 撲克牌
* 從無序序列往有序子序列插入, 插入排序改進版 不足: 移動太頻繁
*/
public static int[] InsertSort(int[] arr) {
// 無序序列
// 忽略首位,從1開始
for (int i = 1; i < arr.length; i++) {
int temp = arr[i];
int j;
// 有序序列
// 最早從0開始比對
for (j = i - 1; j >= 0 && temp < arr[j]; j--) {
// j 后面的往后挪
arr[j + 1] = arr[j];
}
arr[j + 1] = temp;
}
return arr;
}
/*
* SHELL 希爾排序
* 插入排序改進版
*
*/
public static int[] ShellSort(int[] arr) {
// 取增量
int step = arr.length / 2;
while (step >= 1) {
// 還是忽略0位
// 0...step 1...step+1
for (int i = step; i < arr.length; i++) {
int temp = arr[i];
int j = 0;
// 跟插入排序的區別就在這里
for (j = i - step; j >= 0 && temp < arr[j]; j -= step) {
arr[j + step] = arr[j];
}
arr[j + step] = temp;
}
step /= 2;
}
return arr;
}
/*
*
*歸並排序
*分到最細了,就剩兩個數,歸並,依次類推
* 本質是靠歸並(有序的merge)排的序
*
*/
public static int[] mergeSort(int[] arr, int[] tempArray, int left,
int right) {
if (left < right) {
// 取分割位置
int middle = (left + right) / 2;
// 遞歸划分數組左序列
mergeSort(arr, tempArray, left, middle);
// 遞歸划分數組右序列
mergeSort(arr, tempArray, middle + 1, right);
Merge(arr, tempArray, left, middle + 1, right);
}
return arr;
}
private static void Merge(int[] arr, int[] tempArray, int left, int middle,
int right) {
int leftEnd = middle - 1;
int rightStart = middle;
// 臨時數組的下標
int tempIndex = left;
// 數組合並厚的length長度
int tempLength = right - left + 1;
// 先循環兩個區間段都沒有結束的情況
while ((left <= leftEnd) && (rightStart <= right)) {
// 左邊的比右邊的小,先插入左邊的
if (arr[left] < arr[rightStart]) {
tempArray[tempIndex++] = arr[left++];
} else {
tempArray[tempIndex++] = arr[rightStart++];
}
}
// 判斷左序列是否結束
while (left <= leftEnd) {
tempArray[tempIndex++] = arr[left++];
}
// 判斷右序列是否結束
while (rightStart <= right) {
tempArray[tempIndex++] = arr[rightStart++];
}
// 交換數據
for (int i = 0; i < tempArray.length; i++) {
arr[right] = tempArray[right];
right--;
}
}
public static void main(String[] args) {
int[] arr // = { 5, 9, 3, 7, 2, 1,6 };
= new int[100];
Random random = new Random();
random.setSeed(System.currentTimeMillis());
for (int i = 0; i < 100; i++) {
arr[i] = random.nextInt(1000);
}
System.out.println("begin");
// quickSort(arr, 0, arr.length - 1);
// selectionSort(arr);
InsertSort(arr);
for (int e : arr) {
System.out.print(e + " ");
}
}
}