歸並排序及優化(Java實現)
阿新 • • 發佈:2017-12-01
繼續 soft local == else 歸並排序 right 數據 cal
普通歸並排序
public class MergeSort { /** * @param arr 待排序的數組 * @param left 本次歸並的左邊界 * @param mid 本次歸並的中間位置,也就是分界線 * @param right 本次歸並的右邊界 * @param <T> 泛型 * @local aux 輔助空間(Auxiliary Space) */ private static <T extends Comparable<? super T>> void merge(T[] arr, int left, int mid, int right) { T[] aux = java.util.Arrays.copyOfRange(arr, left, right + 1); //aux,i j分別是這兩半的起始指針。將這兩個閉區間歸並[left ... mid] [mid + 1 ... right] int i = left; int j = mid + 1; for (int t = left; t <= right; t++) {//把arr數組中的[left...right]區間都覆蓋了,就完事了 if (i > mid) { //i == mid + 1 時越界(躍出左半數組) arr[t] = aux[j++ - left]; } else if (j > right) {//j == right + 1 時越界(躍出右半數組) arr[t] = aux[i++ - left]; } else if (aux[i - left].compareTo(aux[j - left]) < 0) {//如果i-left小,那麽插入。(左半邊數組的指針所指的數小) arr[t] = aux[i++ - left]; } else { //如果j-left小,那麽插入。(右半邊數組的指針所指的數小) arr[t] = aux[j++ - left]; } } } private static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) { if (left >= right) { return; } int mid = (left + right) / 2; sort(arr, left, mid); sort(arr, mid + 1, right); merge(arr, left, mid, right); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } private static void printArr(Object[] arr) { for (Object o : arr) { System.out.print(o); System.out.print("\t"); } System.out.println(); } public static void main(String args[]) { Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6}; printArr(arr);//3 5 1 7 2 9 8 0 4 6 sort(arr); printArr(arr);//0 1 2 3 4 5 6 7 8 9 } }
歸並優化:利用插入排序
當遞歸到規模足夠小時,利用插入排序
public class MergeSort { /** * @param arr 待排序的數組 * @param left 本次歸並的左邊界 * @param mid 本次歸並的中間位置,也就是分界線 * @param right 本次歸並的右邊界 * @param <T> 泛型 * @local aux 輔助空間(Auxiliary Space) */ private static <T extends Comparable<? super T>> void merge(T[] arr, int left, int mid, int right) { T[] aux = java.util.Arrays.copyOfRange(arr, left, right + 1); //aux,i j分別是這兩半的起始指針。將這兩個閉區間歸並[left ... mid] [mid + 1 ... right] int i = left; int j = mid + 1; for (int t = left; t <= right; t++) {//把arr數組中的[left...right]區間都覆蓋了,就完事了 if (i > mid) { //i == mid + 1 時越界(躍出左半數組) arr[t] = aux[j++ - left]; } else if (j > right) {//j == right + 1 時越界(躍出右半數組) arr[t] = aux[i++ - left]; } else if (aux[i - left].compareTo(aux[j - left]) < 0) {//如果i-left小,那麽插入。(左半邊數組的指針所指的數小) arr[t] = aux[i++ - left]; } else { //如果j-left小,那麽插入。(右半邊數組的指針所指的數小) arr[t] = aux[j++ - left]; } } } /** * @param arr 當規模小的時候對arr采用插入排序 * @param left 待排序部分的左邊界 * @param right 待排序部分的右邊界 * @param <T> 泛型 */ private static <T extends Comparable<? super T>> void insertionSort(T[] arr, int left, int right) { for (int i = left + 1; i <= right; i++) { T temp = arr[i]; int j = i - 1; while (j >= 0 && temp.compareTo(arr[j]) < 0) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = temp; } } private static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) { if (right - left < 7) { //對小規模數據進行插入排序 insertionSort(arr, left, right); return; } int mid = (left + right) / 2; sort(arr, left, mid); sort(arr, mid + 1, right); merge(arr, left, mid, right); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } private static void printArr(Object[] arr) { for (Object o : arr) { System.out.print(o); System.out.print("\t"); } System.out.println(); } public static void main(String args[]) { Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6}; printArr(arr);//3 5 1 7 2 9 8 0 4 6 sort(arr); printArr(arr);//0 1 2 3 4 5 6 7 8 9 } }
歸並排序繼續優化:歸並前判斷一下是否還有必要歸並
public class MergeSort { /** * @param arr 待排序的數組 * @param left 本次歸並的左邊界 * @param mid 本次歸並的中間位置,也就是分界線 * @param right 本次歸並的右邊界 * @param <T> 泛型 * @local aux 輔助空間(Auxiliary Space) */ private static <T extends Comparable<? super T>> void merge(T[] arr, int left, int mid, int right) { T[] aux = java.util.Arrays.copyOfRange(arr, left, right + 1); //aux,i j分別是這兩半的起始指針。將這兩個閉區間歸並[left ... mid] [mid + 1 ... right] int i = left; int j = mid + 1; for (int t = left; t <= right; t++) {//把arr數組中的[left...right]區間都覆蓋了,就完事了 if (i > mid) { //i == mid + 1 時越界(躍出左半數組) arr[t] = aux[j++ - left]; } else if (j > right) {//j == right + 1 時越界(躍出右半數組) arr[t] = aux[i++ - left]; } else if (aux[i - left].compareTo(aux[j - left]) < 0) {//如果i-left小,那麽插入。(左半邊數組的指針所指的數小) arr[t] = aux[i++ - left]; } else { //如果j-left小,那麽插入。(右半邊數組的指針所指的數小) arr[t] = aux[j++ - left]; } } } /** * @param arr 當規模小的時候對arr采用插入排序 * @param left 待排序部分的左邊界 * @param right 待排序部分的右邊界 * @param <T> 泛型 */ private static <T extends Comparable<? super T>> void insertionSort(T[] arr, int left, int right) { for (int i = left + 1; i <= right; i++) { T temp = arr[i]; int j = i - 1; while (j >= 0 && temp.compareTo(arr[j]) < 0) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = temp; } } private static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) { // 先註釋掉,為了測試 // if (right - left < 7) { //對小規模數據進行插入排序 // insertionSort(arr, left, right); // return; // } if (left >= right) { return; } int mid = (left + right) / 2; sort(arr, left, mid); sort(arr, mid + 1, right); //在歸並前判斷一下,如果左邊的最大的比右邊的最小的還小(或者等於),那就不用歸並了,已經有序了。 if (arr[mid].compareTo(arr[mid + 1]) <= 0) { return; } merge(arr, left, mid, right); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } private static void printArr(Object[] arr) { for (Object o : arr) { System.out.print(o); System.out.print("\t"); } System.out.println(); } public static void main(String args[]) { Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6}; printArr(arr);//3 5 1 7 2 9 8 0 4 6 sort(arr); printArr(arr);//0 1 2 3 4 5 6 7 8 9 } }
歸並排序及優化(Java實現)