兩個有序數組合並並不難, 可是歸併的思想確實是這個, 可是如何分, 分到什麼時候呢 ?java
這個名字含義就是分爲歸 和 並
兩個階段執行node
先說並吧, 並要求是兩個已經排序好了的數組(兩個連續數組是位置上也連續) , 好比1,2,3,4
, 連續數組1,2
和3,4
, 不能是 1,2
,4
進行排序 ,api
對於兩個已經排序好了的數據, 好處是一次遍歷即可以兩個數組合併成一個有序的數組數組
而後再說 歸吧, 歸的思想就是 , 4,3,2,1
, 先分 4,3
和2,1
, 將4,3
繼續分 4
,3
,此時這就是倆位置有序的數組, 將他倆數組進行並 , 就成了 3,4
, 而後2,1
分爲2
,1
, 此時再將這倆數組排序,此時是1,2
, 而後將3,4
和1,2
進行並排序, 此時就是1,2,3,4
, OK了ui
/** * 歸併排序 * * * @author: <a href='mailto:fanhaodong516@qq.com'>Anthony</a> */ public class MergeSort { public static void main(String[] args) { int[] arr_1000 = Common.generate_Arr_1000(); splitAndMergerSort(arr_1000, 0, arr_1000.length - 1); Common.showArr(arr_1000); } /** * 將[1,2,3]數組分割成直到 [1][2][3]這種 ,遞歸實現 * * @param arr 數組 * @param start 開始位置 ,索引從0開始 * @param end 結束位置 , 索引0開始 */ private static void splitAndMergerSort(int[] arr, int start, int end) { if (start == end) return; int middle = (end + start) >> 1; splitAndMergerSort(arr, start, middle); splitAndMergerSort(arr, middle + 1, end); merge(arr, start, end, middle + 1); } /** * @param arr 數據 * @param start 索引從0開始 , 數組開始位置 * @param end 索引從0開始 , 數組結束位置 * @param delimiter 切割位置 : [1,2,4,5] 參數(arr,0 , 3 , 2) , 分隔符是 (star+end)/2+1 */ private static void merge(int[] arr, int start, int end, int delimiter) { if (start == end) return; // 1. 初始化數組 int llen = delimiter - start; int rlen = (end - delimiter) + 1; int[] left = new int[llen]; int[] right = new int[rlen]; //2. 將分割數組 , 填充數據 System.arraycopy(arr, start, left, 0, llen); System.arraycopy(arr, delimiter, right, 0, rlen); // 3.歸併步驟 int l = 0; int r = 0; int len = end + 1; for (int i = start; i < len; ++i) { if (l < llen && r < rlen) { if (left[l] < right[r]) { arr[i] = left[l]; l++; } else { arr[i] = right[r]; r++; } } else { if (l < llen) { arr[i] = left[l]; l++; } if (r < rlen) { arr[i] = right[r]; r++; } } } } // 第二種合併方式 private static void merge(int[] left_arr, int[] right_arr) { int lL = left_arr.length; int rL = right_arr.length; int resultL = lL + rL; int[] result = new int[resultL]; int l = 0; int r = 0; int w = 0; while (w < resultL) { if (l < lL && r < rL) { if (left_arr[l] < right_arr[r]) { result[w] = left_arr[l]; l++; w++; } else { result[w] = right_arr[r]; r++; w++; } } else { if (l < lL) { System.arraycopy(left_arr, l, result, w, lL - l); break; } if (r < rL) { System.arraycopy(right_arr, r, result, w, rL - r); break; } } } Common.showArr(result); } }
數組他能夠利用索引關係構建出一個徹底二叉樹 , 因此利用這個特性很好的組成堆,code
堆排序 分爲兩個階段排序
一階段 : 堆化 - > 將數據轉換成 大頂堆或者小頂堆 , 就是根節點數據大於子葉數據 , 就是大頂堆.遞歸
二階段 : 利用大頂堆或者小頂堆進行排序 , 就是將堆頂和最後一個數據進行交換, 由於堆頂是最大值或者最小值, 而後堆化, 重複操做 ,索引
/** * 堆排序 * * @author: <a href='mailto:fanhaodong516@qq.com'>Anthony</a> */ public class HeapSort { public static void main(String[] args) { int[] arr_1000 = Common.generate_Arr_1000(); heap_sort(arr_1000, arr_1000.length); Common.showArr(arr_1000); } /** * 堆排序 * * @param tree * @param n */ static void heap_sort(int[] tree, int n) { // 1. 構建一個堆 build_heap(tree, n); // 2. // 堆頂和最後一個節點作交換 , 可是咱們須要在數組上截取 , 因此就是每次 for (int i = n - 1; i >= 0; i--) { // 交換節點 swap(tree, i, 0); // 第0個位置 開始堆從新排序 heapify(tree, i, 0); } } /** * 構建一個 大頂堆 * * @param tree * @param n */ static void build_heap(int[] tree, int n) { // 最後一個節點 int last_node = n - 1; // 開始遍歷的位置是 : 最後一個堆的堆頂 , 意思就是 , 整個樹中最小的一個堆 , 其實就是最後一個節點的父節點 int parent = (last_node - 1) / 2; // 遞減向上遍歷 for (int i = parent; i >= 0; i--) { heapify(tree, n, i); } } /** * @param tree 表明一棵樹 * @param n 表明多少個節點 * @param i 對哪一個節點進行 heapify */ static void heapify(int[] tree, int n, int i) { // 若是當前值 大於 n 直接返回了 ,通常不會出現這種問題 ..... if (i >= n) { return; } // 子節點 int c1 = 2 * i + 1; int c2 = 2 * i + 2; // 假設最大的節點 爲 i (父節點) int max = i; // 若是大於 賦值給 max if (c1 < n && tree[c1] > tree[max]) { max = c1; } // 若是大於 賦值給 max if (c2 < n && tree[c2] > tree[max]) { max = c2; } // 若是i所在的就是最大值咱們不必去作交換 if (max != i) { // 交換最大值 和 父節點 的位置 swap(tree, max, i); // 交換完之後 , 此時的max其實就是 i原來的數 ,就是最小的數字 ,因此須要遞歸遍歷 heapify(tree, n, max); } } static void swap(int[] tree, int max, int i) { int temp = tree[max]; tree[max] = tree[i]; tree[i] = temp; } }
其實我認爲他是 區間排序, 舉個例子 [1,2,3,4,5,6]
, 將他放入6個區間內 , (0,1] ,(1,2] , 依次到最後 , 那麼這個放置過程徹底是能夠經過計算獲得的. 因此一次遍歷即可以完成排序 , 若是區間內部排序, 能夠選擇其餘排序方式.it
package com.sort; import java.util.Arrays; /** * 桶排序 ,其實就是區間排序 1,2,3,4,5,6 ,咱們分紅 0-3, 3-6的區間(首先區間是有順序的) * , 1,2,3 進去區間一, 4,5,6進去區間二 , 而後區間內排序, 此時就構建了新的數組 * * * @author: <a href='mailto:fanhaodong516@qq.com'>Anthony</a> */ public class BucketSort { public static void main(String[] args) { int[] arr_1000 = Common.generate_Arr_1000(); bucketSort(arr_1000, 10); Common.showArr(arr_1000); } /** * @param arr 數組 * @param bucketCount 桶的個數 */ public static void bucketSort(int[] arr, int bucketCount) { int len = arr.length; if (len <= 1 || bucketCount <= 0) { return; } // 遍歷一次找到最大值 最小值 int max = arr[0], min = arr[0]; for (int i : arr) { if (i > max) { max = i; } if (i < min) { min = i; } } /** * 劃分區間 , 好比 5 - 11 ,此時咱們須要 / 桶數量 (假如 是 2), 若是咱們不+1 , 6 / 2 = 3 ,那麼 (11-5)/3=2 , 此時座標2這個桶 * * 因此區間須要+1 操做 , 因此上面就是 7/2=3.5=4 , (11-5)/4=1 */ int range = ((max - min + 1) % bucketCount) == 0 ? (max - min + 1) / bucketCount : (max - min + 1) / bucketCount + 1; // 建立桶 ,是一個二維數組 int[][] bucket = new int[bucketCount][]; for (int i : arr) { bucket[(i - min) / range] = arrAppend(bucket[(i - min) / range], i); } for (int[] ints : bucket) { sort(ints); } int count = 0; for (int[] ints : bucket) { if (ints != null) { for (int anInt : ints) { arr[count++] = anInt; } } } } /** * 數組拷貝 * * @param arr * @param value * @return */ private static int[] arrAppend(int[] arr, int value) { //數組若是爲空, 新建一個數組, if (arr == null) { arr = new int[0]; } // 數組拷貝 , 其實就是長度+1 arr = Arrays.copyOf(arr, arr.length + 1); // 將值複製 arr[arr.length - 1] = value; //返回 return arr; } private static void sort(int[] arr) { /** * 空 或者 0 / 1 都直接返回 */ if (null == arr || arr.length <= 1) { return; } // 2 3 1 for (int index = 1; index < arr.length; index++) { // 當前位置 , 開始必須從第二個開始 int temp = arr[index]; // 左邊位置 int left = index - 1; // 移動座標其實就是 ... while (left >= 0 && arr[left] > temp) { // 互換位置 arr[left + 1] = arr[left]; // 向前移動 left--; } // 最後保存數據 arr[left + 1] = temp; } } }
我沒有寫, 他和桶排序相似 , 一次比較個位數 , 十位數 , 百位數數據, 分紅10個桶 , 對號入座, 第一遍比較個位數, 第二遍比較十位數, 第三遍比較百位數 .