氣泡排序、選擇排序、插入排序、歸併排序演算法
阿新 • • 發佈:2019-01-07
最近了解了一下在面試題中,會經常遇到的一些常見的簡單的排序的演算法
在這裡做個簡單的記錄如有不對之處請多指教。
1、氣泡排序
演算法思想:氣泡排序是對陣列中相鄰的兩個元素進行比較,看是否滿足大小關係,不滿足的話就交換位置
每次氣泡排序至少有一個元素到達指定位置,也至少會發生一次位置交換(如果沒有位置交換就說明陣列有序),
有n個數據,需要重複n次
最好、最壞、平均時間複雜度:
最好時間複雜度(是一個有序陣列時)為O(n)
最壞時間複雜度(剛好倒序時)為O(n2)
平均時間複雜度:O(n2)
程式碼示例:
1 public static void bubbleSort(int[] arr) { 2 for (int i = 0; i < arr.length - 1; i++) { 3 for (int j = 0; j < arr.length - 1 - i; j++) { 4 if(arr[j] > arr[j+1]) { 5 int temp = arr[j]; 6 arr[j] = arr[j + 1]; //資料交換7 arr[j+1] = temp; 8 } 9 } 10 } 11 }
氣泡排序的一些小的優化:當某次冒泡,沒有再進行資料的交換時,說明陣列已經有序,就可以不用進行後面的冒泡操作了
程式碼示例:
1 public static void bubbleSort(int[] arr) { 2 3 if(arr.length <= 1) return; 4 5 for(int i = 0;i < arr.length - 1;i++) {6 boolean flag = false; //提前退出迴圈的標誌 7 for(int j = 0;j < arr.length - i -1;j++) { 8 if(arr[j] > arr[j + 1]) { 9 int temp = arr[j]; 10 arr[j] = arr[j + 1]; //資料交換 11 arr[j + 1] = temp; 12 flag = true; //表示有資料交換 13 } 14 } 15 if (!flag) break; //如果沒有資料交換的話退出迴圈 16 } 17 }
執行結果:
2、選擇排序
演算法思想:在未排序區間尋找最小的資料,將其放到已排好序區間的元素的尾部
最好、最壞、平均時間複雜度:
最好時間複雜度:O(n2)
最壞時間複雜度:O(n2)
平均時間複雜度:O(n2)
程式碼示例:
1 public static void selectionSort(int[] arr) { 2 for(int i = 0;i < arr.length - 1;i++) { 3 int minIndex = i; 4 //選出未排序區間的最小元素 5 for (int j = i + 1; j < arr.length; j++) { 6 if(arr[j] < arr[minIndex]) { 7 minIndex = j; 8 } 9 } 10 if(minIndex == i) 11 continue; 12 //交換位置 13 int temp = arr[i]; 14 arr[i] = arr[minIndex]; 15 arr[minIndex] = temp; 16 } 17 18 }
執行結果:
3、插入排序
演算法思想:我們將元素分為兩個區間,未排序區間和已排序區間。
在未排序區間取出元素與已排序區間元素進行比較插入到適當位置,
以此類推,直到未排序區間為空為止
最好時間複雜度:(陣列有序)O(n)
最壞時間複雜度:(剛好倒序)O(n2)
平均時間複雜度:O(n2)
4、歸併排序
演算法思想:利用歸併的思想方法實現的一種有效的排序方法,採用經典的分治策略。
最好時間複雜度:O(nlogn)
最壞時間複雜度:O(nlogn)
平均時間複雜度:O(nlogn)
程式碼示例:
1 public class MergeSort { 2 public static void main (String[] args) { 3 int[] arr = {56,12,97,58,64,25}; 4 sort(arr); 5 print(arr); 6 } 7 8 public static void print(int[] arr) { 9 for(int i = 0;i < arr.length;i++){ 10 System.out.print(arr[i] + " "); 11 } 12 } 13 14 public static void sort(int[] arr) { 15 int[] temp = new int[arr.length]; //定義一個臨時陣列,避免遞迴時頻繁開闢空間 16 sort(arr,0,arr.length - 1,temp); 17 } 18 19 20 public static void sort(int[] arr,int left,int right,int[] temp) { 21 if(left < right){ 22 int mid = (left + right) / 2; 23 sort(arr,left,mid,temp); //左歸併操作 24 sort(arr,mid + 1,right,temp); //右歸併操作 25 mergeSort(arr,left,mid,right,temp); 26 27 } 28 29 } 30 31 //合併子序列的操作 32 private static void mergeSort(int[] arr,int left,int mid,int right,int[] temp) { 33 int i = left; 34 int j = mid + 1; 35 int k = 0; 36 37 while(left <= mid && j <= right) { //將子序列元素有序寫入臨時陣列 38 if(arr[i] >= arr[j]) { 39 temp[k++] = arr[j++]; 40 } else { 41 temp[k++] = arr[i++]; 42 } 43 44 } 45 46 while(i <= mid) { //將左子序列元素全部寫入臨時陣列中 47 temp[k++] = arr[i++]; 48 } 49 50 while(j <= right) { //將右子序列元素全部寫入臨時陣列中 51 temp[k++] = arr[j]; 52 53 } 54 55 for (int t = 0;left <= right;t++) { 56 arr[left++] = temp[t]; 57 } 58 } 59 60 }
合併子序列的操作圖解。可以用Debug除錯,進入程式檢視具體的運算,這裡只做個簡單的圖解。
執行的結果: