圖解排序演算法
最近覺得自己的程式設計毫無進展,想修煉下自己的內功,於是就開始複習學習資料結構與演算法。其實,程式設計的人大概都知道一句話“程式等於演算法+資料結構”,理解並選用合適的資料結構,還有演算法,是編寫出優秀程式的前提。在JAVA JDK中,也可以窺探出資料結構演算法的重要性,比如HashMap中就用到了陣列+連結串列提高查詢、插入效率。個人也想通過總結編寫文章的方式提高學習效率,於是有這篇文章。為了逼自己一把,決定以後每週寫一篇部落格(不一定都是資料結構與演算法)。由於鄙人水平有限,加之文采極差,還很少寫部落格,希望看到文章的各位大佬能提提看法、建議。
一、氣泡排序
1、說明
氣泡排序,每次冒泡都比較相鄰兩個數的大小,大小關係不對,則交換。如下圖,第一躺冒泡下來,最大的值都會被排到正確的位置,也有可能有其他數字處於正確位置。所以一趟下來至少有一個最大的處於正確位置(如下圖的9)。
第二趟下來,第一趟後剩下的數字中,最大的8又會處於正確位置(如下圖)。
這樣最多冒泡n-1次,就會是一個有序的序列
2、JAVA程式碼實現如下
//時間複雜度為O(n^2) 最好時間複雜度O(n) 平均時間複雜度O(n^2) public static void sort(int numArray[]) { if (numArray == null || numArray.length == 0) { return; } int arrayLength = numArray.length; int tmp; //這一趟是否有發生交換,如果沒有發生交換,說明陣列已經是有序的,不需要再冒泡了。 boolean flag = false; //外層:需要length-1次迴圈比較,需要做n-1次冒泡 for(int i= 0; i < arrayLength - 1; i++) { flag = false; for(int j=0; j < arrayLength -i-1; j++) { //內層:每次迴圈需要兩兩比較的次數,每次比較後,都會將當前最大的數放到最後位置 if(numArray[j] > numArray[j+1]) { tmp = numArray[j]; numArray[j] = numArray[j+1]; numArray[j+1] = tmp; flag = true; } } if(!flag) //沒有任何交換,陣列已經處於有序 break; } } 複製程式碼
二、選擇排序
1、說明
選擇排序如下圖,每次都找出剩餘中最小的值,將該最小值放到正確位置
2、JAVA程式碼實現如下
public static void selectSort(int numArray[]) { int length = numArray.length; int min,pos; //每一次迴圈都會找出剩下中的最小數,放到正確的位置 for(int i= 0; i < length-1; i++) { min = numArray[i]; pos = i; //找出剩餘中的最小數 for(int j = i+1; j < length; j++) { if(numArray[j] < min) { min = numArray[j]; pos = j; } } if(pos != i) { numArray[pos] = numArray[i]; numArray[i] = min; } } }複製程式碼
三、插入排序
1、說明
插入排序同我們打撲克牌時排序牌一樣,每次抽上一張牌,插入到手上已經有序的牌中。如下例子,我們從第二個數開始,插入到前面中。如下圖,第二次,6需要插入到前面5,8之間,所以將8後移,之後將6插入。
2、JAVA程式碼實現如下
public static void insertSort(int intList[]) { int j = 1; int i; for(; j < intList.length; j++) { i = j-1; int key = intList[j]; while(i > -1 && intList[i] > key) { intList[i+1] = intList[i]; i--; } intList[i+1] = key; } //時間複製度為O(n^2) ,最好情況時間複雜度O(n),平均時間複雜度O(n^2) }複製程式碼
四、快速排序
1、說明
快速排序採用分治的思想,總的思想就是選取一個數字為基準值,並將所有比它小的元素放到它前面,比它大的元素放到它後面,之後基準值就處於正確位置,分別對基準值前後兩個陣列進行排序,最後就會是有序的。快速排序有多種實現方式,以下是通過左右指標實現。
2、 JAVA程式碼實現如下
public static void quickSort(int numArray[],int _left, int _right) { int left = _left; int right = _right; int temp = 0; if(left <= right){//待排序的元素至少有兩個的情況 temp = numArray[left];//待排序的第一個元素作為基準元素 while(left != right){//從左右兩邊交替掃描,直到left = right while(right > left && numArray[right] >= temp) right --;//從右往左掃描,找到第一個比基準元素小的元素 numArray[left] = numArray[right];//找到這種元素arr[right]後與arr[left]交換 while(left < right && numArray[left] <= temp) left ++;//從左往右掃描,找到第一個比基準元素大的元素 numArray[right] = numArray[left];//找到這種元素arr[left]後,與arr[right]交換 } numArray[right] = temp;//基準元素歸位 quickSort(numArray,_left,left-1);//對基準元素左邊的元素進行遞迴排序 quickSort(numArray, right+1,_right);//對基準元素右邊的進行遞迴排序 } }複製程式碼
五、歸併排序
1、說明
歸併排序也是分治思想,先將所有元素分離開,並進行逐步排序,原理如下圖
2、 JAVA程式碼實現如下
public static int[] sort(int [] a) { if (a.length <= 1) { return a; } int num = a.length >> 1; int[] left = Arrays.copyOfRange(a, 0, num); int[] right = Arrays.copyOfRange(a, num, a.length); return mergeTwoArray(sort(left), sort(right)); } public static int[] mergeTwoArray(int[] a, int[] b) { int i = 0, j = 0, k = 0; int[] result = new int[a.length + b.length]; // 申請額外空間儲存歸併之後資料 while (i < a.length && j < b.length) { //選取兩個序列中的較小值放入新陣列 if (a[i] <= b[j]) { result[k++] = a[i++]; } else { result[k++] = b[j++]; } } while (i < a.length) { //序列a中多餘的元素移入新陣列 result[k++] = a[i++]; } while (j < b.length) {//序列b中多餘的元素移入新陣列 result[k++] = b[j++]; } System.out.println(Arrays.toString(result)); return result; } 複製程式碼