linux如何把新加的分割槽掛載到/根目錄
排序大的分類可以分為兩種:內排序和外排序。在排序過程中,全部記錄存放在記憶體,則稱為內排序。如果排序過程中需要使用外存,則稱為外排序。下面講的排序都是屬於內排序。
一、插入排序
(一)、直接插入排序
public class Sort { public static void main(String[] args) { int[] arr = {1, 3, 51, 65, 6, 34, 67, 343, 56}; int[] sortResult = insertionSort(arr); System.out.println(Arrays.toString(sortResult)); }/** * 用一個臨時變數儲存待插入的值,從後往前找,如果找到比這個值大的元素,則將其前面的元素依次後移, * 結束後再將帶插入的值放到該插入的位置,減去了許多不必要的交換操作 * @param arr * @return */ public static int[] insertionSort(int[] arr) { for (int i = 1; i < arr.length; i++) { //待插入元素 int insertValue = arr[i];int preIndex = i - 1; while (preIndex >= 0 && insertValue < arr[preIndex]) { arr[preIndex + 1] = arr[preIndex]; preIndex--; } arr[preIndex + 1] = insertValue; } return arr; } }
(二)、希爾排序(shell排序)
publicclass Sort { public static void main(String[] args) { int[] arr = {1, 3, 51, 65, 6, 34, 67, 343, 56}; int[] sortResult = shellSort(arr); System.out.println(Arrays.toString(sortResult)); } /** * 希爾排序 * 插入排序的升級版,設定步長為陣列長度的一半,每次都除以二,直到步長為1 * @param arr * @return */ public static int[] shellSort(int[] arr) { int len = arr.length; for (int k = len / 2; k > 0; k /= 2) { for (int i = k; i < len; i++) { int temp = arr[i]; int j = i - k; while (j >= 0 && temp < arr[j]) { arr[j + k] = arr[j]; j -= k; } arr[j + k] = temp; } } return arr; } }
二、選擇排序
(一)、簡單選擇排序(直接排序)
public class Sort { public static void main(String[] args) { int[] arr = {1, 3, 51, 65, 6, 34, 67, 343, 56}; int[] sortResult = selectionSort(arr); System.out.println(Arrays.toString(sortResult)); } /** * 遍歷陣列,每次遍歷都找到最小的元素,記錄其下標,內層迴圈結束後再根據下標將其與陣列頭部元素交換 * 與氣泡排序不同的是,氣泡排序每次迴圈可能交換多次,而選擇排序最多交換一次 * @param arr 待排序陣列 * @return */ public static int[] selectionSort(int[] arr) { int temp, minIndex; for (int i = 0; i < arr.length - 1; i++) { minIndex = i; for (int j = i + 1; j < arr.length; j++) { if (arr[j] < arr[minIndex]) { minIndex = j; } } temp = arr[minIndex]; arr[minIndex] = arr[i]; arr[i] = temp; } return arr; } }
(二)、堆排序
public class HeapSort { public static void main(String[] args) { int[] arr = {1, 3, 51, 65, 6, 34, 67, 343, 56}; int[] sortResult = heapSort(arr); System.out.println(Arrays.toString(sortResult)); } public static int[] heapSort(int[] arr) { //以最後一個非葉子結點構建大頂堆 for (int i = arr.length / 2 - 1; i >= 0; i--) { adjustHeap(arr, i, arr.length); } //此時頂部元素是最大的,交換頂部元素和末端元素 for (int i = arr.length - 1; i > 0; i--) { swap(arr, 0, i); //末端元素已經是最大的了,無需考慮排序 adjustHeap(arr, 0, i); } return arr; } /** * 形成大頂堆 * * @param arr 陣列元素 * @param i 當前結點位置 * @param len 結點個數 */ public static void adjustHeap(int[] arr, int i, int len) { //儲存當前結點 int temp = arr[i]; //遍歷當前結點的左子結點 for (int k = 2 * i + 1; k < len; k = 2 * k + 1) { //如果右結點存在 且 右結點比左結點大,指向右結點 if (k + 1 < len && arr[k] < arr[k + 1]) { k++; } //判斷當前結點和左(右)結點哪個大 if (temp < arr[k]) { //交換 swap(arr, k, i); //交換後,下次遍歷以該子結點作為根節點的子樹就會受到影響,因此需要重新指定下次的根節點 i = k; } else { //不用交換,直接終止迴圈 break; } } } public static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
三、交換排序
(一)、氣泡排序
/** * 遍歷陣列,依次比較相鄰的元素並交換,每次都將最大元素(根據正序還是逆序決定)放到陣列末尾 * @param arr 待排序陣列 * @return */ public static int[] bubbleSort(int[] arr) { int temp; for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } return arr; }
氣泡排序優化一:
//氣泡排序:優化一 public static int[] bubbleSort1(int[] arr) { int temp; //記錄陣列是否有序 boolean isSorted; for (int i = 0; i < arr.length - 1; i++) { isSorted = true; for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; //記錄本輪排序是否交換了元素,如果交換則置為false isSorted = false; } } //沒有交換證明已經是有序的了,直接終止迴圈 if (isSorted) { break; } } return arr; }
氣泡排序優化二:
//氣泡排序:優化二 public static int[] bubbleSort2(int[] arr) { int temp; boolean isSorted; //第一次迴圈邊界 int sortBorder = arr.length - 1; //記錄每輪排序最後一次進行交換的位置 int lastSwapIndex = 0; for (int i = 0; i < arr.length - 1; i++) { isSorted = true; for (int j = 0; j < sortBorder; j++) { if (arr[j] > arr[j + 1]) { temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; isSorted = false; lastSwapIndex = j; } } sortBorder = lastSwapIndex; if (isSorted) { break; } } return arr; }
(二)、快速排序
演算法原理:先在陣列中選擇一個數字,通過一趟排序將要排序的資料分割成獨立的兩部分:比選擇的數字小的數字都移到陣列的左邊,比選擇的數字大的數字都移到陣列的右邊。然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。
快速排序中基準的選取:
1. 第一個元素或最後一個元素,但是當陣列中的元素原本為逆序時,升序排序就會變成一次只能確定基準元素的位置,無法發揮快排的優勢
2. 隨機選取
3. 三數取中法,也就是取左端、中間、右端三個數,然後進行排序,將中間數作為樞紐值。
舉個栗子:
原陣列:{3,7,2,9,1,4,6,8,10,5}
期望結果:{1,2,3,4,5,6,7,8,9,10}
快速排序示意圖:
程式碼實現:
public class QuickSort { public static int divide(int[] a, int start, int end){ //每次都以最右邊的元素作為基準值 int base = a[end]; //start一旦等於end,就說明左右兩個指標合併到了同一位置,可以結束此輪迴圈。 while(start < end){ while(start < end && a[start] <= base) //從左邊開始遍歷,如果比基準值小,就繼續向右走 start++; //上面的while迴圈結束時,就說明當前的a[start]的值比基準值大,應與基準值進行交換 if(start < end){ //交換 int temp = a[start]; a[start] = a[end]; a[end] = temp; //交換後,此時的那個被調換的值也同時調到了正確的位置(基準值右邊),因此右邊也要同時向前移動一位 end--; } while(start < end && a[end] >= base) //從右邊開始遍歷,如果比基準值大,就繼續向左走 end--; //上面的while迴圈結束時,就說明當前的a[end]的值比基準值小,應與基準值進行交換 if(start < end){ //交換 int temp = a[start]; a[start] = a[end]; a[end] = temp; //交換後,此時的那個被調換的值也同時調到了正確的位置(基準值左邊),因此左邊也要同時向後移動一位 start++; } } //這裡返回start或者end皆可,此時的start和end都為基準值所在的位置 return end; } /** * 排序 * @param a * @param start * @param end */ public static void sort(int[] a, int start, int end){ if(start > end){ //start >= end ? //如果只有一個元素,就不用再排下去了 return; } else{ //如果不止一個元素,繼續劃分兩邊遞迴排序下去 int partition = divide(a, start, end); sort(a, start, partition-1); sort(a, partition+1, end); } } public static void main(String[] args) { // TODO Auto-generated method stub int[] a = new int[]{2,7,4,5,10,1,9,3,8,6}; int[] b = new int[]{1,2,3,4,5,6,7,8,9,10}; int[] c = new int[]{10,9,8,7,6,5,4,3,2,1}; int[] d = new int[]{1,10,2,9,3,2,4,7,5,6}; int[] e = {3}; sort(b, 0, b.length-1); System.out.println("排序後的結果:"); for(int x : b){ System.out.print(x+" "); } } }
四、歸併排序
public class Sort { public static void main(String[] args) { int[] arr = {1, 3, 51, 65, 6, 34, 67, 343, 56}; int[] sortResult = mergeSort(arr); System.out.println(Arrays.toString(sortResult)); } //歸併排序 public static int[] mergeSort(int[] arr) { return mergeSort(arr, 0, arr.length - 1, new int[arr.length]); } /** * 歸併排序通過遞迴將陣列分解為只有兩個元素,按照它們的大小放入到一個臨時陣列中,直到全部合併 * * @param arr 待排序陣列 * @param left 左索引 * @param right 右索引 * @param temp 臨時陣列,儲存每次合併後的元素 * @return */ public static int[] mergeSort(int[] arr, int left, int right, int[] temp) { if (left < right) { int mid = (left + right) >> 1; //向左分解 mergeSort(arr, left, mid, temp); //向右分解 mergeSort(arr, mid + 1, right, temp); //合併 merge(arr, left, mid, right, temp); } return arr; } //合併 public static int[] merge(int[] arr, int left, int mid, int right, int[] temp) { int i = left, j = mid + 1, k = 0; //按大小放入臨時陣列中 while (i <= mid && j <= right) { if (arr[i] < arr[j]) { temp[k] = arr[i]; k++; i++; } else { temp[k] = arr[j]; k++; j++; } } //將剩餘元素放到temp剩餘位置 while (i <= mid) { temp[k] = arr[i]; k++; i++; } while (j <= right) { temp[k] = arr[j]; k++; j++; } //將排好序的temp陣列元素賦值給原陣列 k = 0; int l = left; while (l <= right) { arr[l] = temp[k]; k++; l++; } return arr; } }
五、基數排序
public class RadixSort { public static void main(String[] args) { int[] arr = {1, 3, 51, 65, 6, 34, 67, 343, 56}; int[] sortResult = radixSort(arr); System.out.println(Arrays.toString(sortResult)); } /** * 基數排序: * 根據每個數的個位、十位、百位...的值(0~9)放入桶中(規則和計數排序相同),因此需要10個桶 * * @param arr * @return */ public static int[] radixSort(int[] arr) { //建立並初始化10個桶 ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(10); for (int i = 0; i < 10; i++) { bucketList.add(new LinkedList<>()); } //找出資料中最大值 int max = arr[0]; for (int i = 1; i < arr.length; i++) { if (max < arr[i]) { max = arr[i]; } } //獲取最大值的位數 int maxRadix = (max + "").length(); //從個位開始 for (int i = 0; i < maxRadix; i++) { //將待排序元素放入桶中 for (int j = 0; j < arr.length; j++) { //獲取數字對應位上的值 int radix = arr[j] / (int) Math.pow(10, i) % 10; //放入對應的桶中 bucketList.get(radix).add(arr[j]); } //將桶中元素放回原陣列 int k = 0; for (int j = 0; j < 10; j++) { for (Integer number : bucketList.get(j)) { arr[k++] = number; } bucketList.get(j).clear(); } } return arr; } }
另:排序演算法的穩定性
1. 穩定性的定義
假定在待排序的記錄序列中,存在多個具有相同的關鍵字的記錄,若經過排序,這些記錄的相對次序保持不變,即在原序列中,ri=rj,且ri在rj之前,而在排序後的序列中,ri仍在rj之前,則稱這種排序演算法是穩定的;否則稱為不穩定的。
舉個栗子:以{6,2,4,6,1}為例
a[0] | a[1] | a[2] | a[3] | a[4] |
6 | 2 | 4 | 6 | 1 |
有兩個6,a[0]和a[3]。排序結果就有兩種可能:
1 | 2 | 4 | 6 | 6 |
原a[4] | 原a[1] | 原a[2] | 原a[0] | 原a[3] |
原a[4] | 原a[1] | 原a[2] | 原a[3] | 原a[0] |
如果排序結束後,a[0]可以保證一定在a[3]前頭,也就是他們原有的順序不變,那這種排序演算法就是穩定的。反之,如果不能保證原有順序,這種演算法就是不穩定的。
2. 常見演算法的穩定性
堆排序、快速排序、希爾排序、直接選擇排序不是穩定的排序演算法,而基數排序、氣泡排序、直接插入排序、折半插入排序、歸併排序是穩定的排序演算法。
3. 穩定性的意義
1、如果只是簡單的進行數字的排序,那麼穩定性將毫無意義。
2、如果排序的內容僅僅是一個複雜物件的某一個數字屬性,那麼穩定性依舊將毫無意義(所謂的交換操作的開銷已經算在演算法的開銷內了,如果嫌棄這種開銷,不如換演算法好了?)
3、如果要排序的內容是一個複雜物件的多個數字屬性,但是其原本的初始順序毫無意義,那麼穩定性依舊將毫無意義。
4、除非要排序的內容是一個複雜物件的多個數字屬性,且其原本的初始順序存在意義,那麼我們需要在二次排序的基礎上保持原有排序的意義,才需要使用到穩定性的演算法。例如要排序的內容是一組原本按照價格高低排序的物件,如今需要按照銷量高低排序,使用穩定性演算法,可以使得想同銷量的物件依舊保持著價格高低的排序展現,只有銷量不同的才會重新排序。(當然,如果需求不需要保持初始的排序意義,那麼使用穩定性演算法依舊將毫無意義)。
參考:
https://www.cnblogs.com/songjilong/p/12234856.html
https://blog.csdn.net/sunxianghuang/article/details/51872360
https://blog.csdn.net/it_zjyang/article/details/53406764
https://www.cnblogs.com/hydor/p/3530593.html
https://blog.csdn.net/chenliguan/article/details/53037482