參考:https://blog.csdn.net/weixin_40205234/article/details/86699088
https://blog.csdn.net/adusts/article/details/80882649
從執行效率:冒泡排序<選擇排序<插入排序<快速排序。
從穩點性: 快速排序,選擇排序 不穩定; 冒泡排序,插入排序 穩定。
1. 冒泡排序
以升序爲例,兩個相鄰的數比較大小,如果前面的數比後面的數大,那麼交換位置。雙重for循環,外層循環控制輪數,內層循環控制每輪比較的次數,每輪比較會將該輪最大數交換到最後面。
代碼:
public class BubbleSort { public static void main(String[] args) { int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48}; BubbleSort(arr); System.out.println(Arrays.toString(arr)); } public static void BubbleSort(int []arr) { //外層循環控制輪數 for(int i=1;i<=arr.length-1;i++) { //內層循環控制每輪比較的次數 for(int j=1;j<=arr.length-i;j++) { if(arr[j-1]>arr[j]) { //藉助中間變量交換兩個位置上的值 int temp = arr[j-1]; arr[j-1]= arr[j]; arr[j]=temp; } } } } }
動態演示:
2. 選擇排序
以升序爲例,在未排序序列中找到最小元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。
代碼:
public class SelectionSort { private void mian() { int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48}; SelectionSort(arr); System.out.println(Arrays.toString(arr)); } private void SelectionSort(int[] arr) { for(int i =0;i<arr.length-1;i++) { int minIndex = i; for(int j=i;j<arr.length-1;j++) { if(arr[minIndex]>arr[j]) { minIndex = j; //記下目前找到的最小值所在的位置 } } //在內層循環結束,也就是找到本輪循環的最小的數以後,再進行交換 if (minIndex != i){ int temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } } } }
動態演示;
3. 插入排序
- 從第一個元素開始,該元素可以認爲已經被排序;
- 取出下一個元素,在已經排序的元素序列中從後向前掃描;
- 如果該元素(已排序)大於新元素,將該元素移到下一位置;
- 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置;
- 將新元素插入到該位置後;
- 重複步驟2~5。
代碼:
public class InsertSort { public static void main(String[] args) { int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48}; insertionSort(arr); System.out.println(Arrays.toString(arr)); } private static void insertionSort(int []arr){ for(int i=1; i<arr.length; i++){ int preIndex = i-1; int current = arr[i]; while(preIndex>=0 && arr[preIndex]>current){ arr[preIndex+1]=arr[preIndex]; preIndex--; } arr[preIndex+1]=current; } } }
動態演示:
4. 快速排序:
步驟爲:
- 從數列中挑出一個元素,稱爲"基準"(pivot),
- 重新排序數列,所有比基準值小的元素擺放在基準前面,所有比基準值大的元素擺在基準後面(相同的數可以到任何一邊)。在這個分區結束之後,該基準就處於數列的中間位置。這個稱爲分區(partition)操作。
- 遞歸地(recursively)把小於基準值元素的子數列和大於基準值元素的子數列排序。
遞歸到最底部時,數列的大小是零或一,也就是已經排序好了。這個算法一定會結束,因爲在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
代碼:
public class QuickSort { public static void main(String[] args) { int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48}; quickSort(arr,0,arr.length-1); System.out.println(Arrays.toString(arr)); } private static void quickSort(int[] arr, int low, int high) { if (low < high) { // 找尋基準數據的正確索引 int index = getIndex(arr, low, high); // 進行迭代對index之前和之後的數組進行相同的操作使整個數組變成有序 quickSort(arr, 0, index - 1); quickSort(arr, index + 1, high); } } private static int getIndex(int[] arr, int low, int high) { // 基準數據 int tmp = arr[low]; while (low < high) { // 當隊尾的元素大於等於基準數據時,向前挪動high指針 while (low < high && arr[high] >= tmp) { high--; } // 如果隊尾元素小於tmp了,需要將其賦值給low arr[low] = arr[high]; // 當隊首元素小於等於tmp時,向前挪動low指針 while (low < high && arr[low] <= tmp) { low++; } // 當隊首元素大於tmp時,需要將其賦值給high arr[high] = arr[low]; } // 跳出循環時low和high相等,此時的low或high就是tmp的正確索引位置 // 由原理部分可以很清楚的知道low位置的值並不是tmp,所以需要將tmp賦值給arr[low] arr[low] = tmp; return low; // 返回tmp的正確位置 } }
動態演示:
借用下啊哈算法的圖:
i和j分別爲左哨兵和右哨兵,這裏樞紐元定爲6,然後分別從左往右(i++)和右往左(j--)開始遍歷
左哨兵查找比6大的元素,右哨兵查找比6小的元素
第一次交換結果
第二次交換結果
相遇後直接與樞紐元交換
然後再遞歸排序就行