圖解排序演算法
最近覺得自己的程式設計毫無進展,想修煉下自己的內功,於是就開始複習學習資料結構與演算法。其實,程式設計的人大概都知道一句話“程式等於演算法+資料結構”,理解並選用合適的資料結構,還有演算法,是編寫出優秀程式的前提。在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;
}
複製程式碼