1. 程式人生 > >氣泡排序、選擇排序、插入排序、歸併排序演算法

氣泡排序、選擇排序、插入排序、歸併排序演算法

最近了解了一下在面試題中,會經常遇到的一些常見的簡單的排序的演算法

在這裡做個簡單的記錄如有不對之處請多指教。

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除錯,進入程式檢視具體的運算,這裡只做個簡單的圖解。

執行的結果: