圖解排序演算法

justCoding發表於2018-11-04

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


相關文章