簡單演算法——直接插入、冒泡、直接選擇
排序的演算法有很多
其中直接插入排序、直接選擇排序、氣泡排序屬於簡單排序,它們對空間的要求不高,但是時間效率卻不穩定;
本文將介紹三種簡單排序,下一篇會介紹三種簡單排序對應的高階排序快速排序、希爾排序、堆排序
首先做一個公用的元素交換實現函式, 下面的swap呼叫都是這個
/**
* 交換陣列元素
* 交換思想很簡單 數字x y => x=x+y;y=x-y;x=x-y;
* 這種方法不使用臨時變數,能有效降低演算法空間複雜度,但也有缺點,比如可能存在越界風險
* @param arr
* @param a
* @param b
*/
public void swap(int []arr,int a,int b){
arr[a] = arr[a]+arr[b];
arr[b] = arr[a]-arr[b];
arr[a] = arr[a]-arr[b];
}
氣泡排序
這個演算法的名字由來是因為越大的元素會經由交換慢慢“浮”到數列的頂端,故名“氣泡排序”。
基本操作:
1、比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
2、對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一輪,最後的元素應該會是最大的數。
3、針對所有的元素重複以上的步驟,除了最後一個。
4、持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較
如:
原始陣列: 5 3 6 4
第一步:3 5 4 6
第二步:3 4 5 6 (實際到這裡排序已經結束,但是原始的氣泡排序會走完所有的迴圈)
第三步:3 4 5 6
第四步:3 4 5 6
程式實現
int arr[] = {5,3,6,4};
public void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
//每次將最大的數字移到最後,下次迴圈長度-1,再將剩餘陣列中最大的數字移到剩餘陣列長度的後面
for (int j = 0; j < arr.length - i -1; j++) {
if(arr[j] > arr[j + 1]) {
swap(arr, j, j+1 );
}
}
}
// printArr(arr);
}
也可以優化一下,如果排序已經完成,就停止迴圈:
public void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
boolean flag = true;//設定一個標記,若為true,則表示此次迴圈沒有進行交換,也就是待排序列已經有序,排序已然完成。
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr,j,j+1);
flag = false;
}
}
if (flag) {
break;
}
}
}
直接插入排序
基本操作是將一條記錄插入到已排好的有序表中,從而得到一個新的、記錄數量增1的有序表。如:
原始陣列: 5 3 6 4
第一步:5 - - - 3 6 4
第二步:3 5 - - - 6 4 (3和5比較一次)
第三步:3 5 6 - - - 4(6和5比較一次)
第四步: 3 4 5 6 (4和3 5 6 各比較一次)
程式實現
int arr[] = {5,3,6,4};
/**
* 採用直接插入排序 將陣列按升序排列
* @param arr
*/
private void directInsert(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int j = i;
while (j > 0 && arr[j] < arr[j - 1]){//兩層意思:1、如果是第一個元素就放著 不比較也不交換 2、如果後面一個數字小於前面那個 就進行交換
swap(arr, j, j-1);
j--;
}
}
}
也可以這樣實現:
int arr[] = {5,3,6,4};
public void insertSort(int[] arr) {
int j;
for (int i = 0; i < arr.length; i++) {
int tem = arr[i];
for (j = i; j > 0 && tem < arr[j - 1]; j--) {
arr[j] = arr[j - 1];
}
arr[j] = tem;
}
//printArr(arr);
}
直接選擇排序
基本思想是:第一輪遍歷中從R[0]~R[n-1]的陣列中選取最小值,與R[0]交換;第二輪從陣列R[1]~R[n-1]中遍歷選取最小值,與R[1]交換,…..,第n-1次從R[n-2]~R[n-1]中選取最小值,與R[n-2]交換,總共通過n-1次,得到升序序列。如:
原始陣列: 5 3 6 4
第一輪:[ 3 ] 5 6 4 (選出最小值3 和第一個數字5交換)
第二輪:[ 3 4 ] 6 5 (選出最小值4 和第二個數字5交換)
第三輪:[ 3 4 5 ] 6 (選出最小值5 和第三個數字6交換 )
第四輪:[ 3 4 5 6 ]
程式實現
public void straightSelection(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int tem = i;//存放較小元素下標
for (int j = i + 1; j < arr.length; j++){
if (arr[j] < arr[tem]) {
tem = j;
}
}
if (tem != i) {
swap(arr, i, tem);
}
}
printArr(arr);
}
以上三種排序都是簡單排序,都具有穩定性,時間複雜度為O(n^2)。平均空間複雜度為O(1)。