徹底弄明白之數據結構中的排序七大算法-java實現


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 + " ");

}

 

}

 

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM