1. 程式人生 > >用分解的方式學算法001——選擇排序

用分解的方式學算法001——選擇排序

索引 true 比較 index bsp 我想 第一步 其他 change

我們在學習算法時,經常遇到的一個問題是,看的懂但是寫不出來。究其原因,是沒有理解到位。

那麽怎麽才能理解到位呢?我認為關鍵是“分解”,就是把算法中的節點按層次和步驟分解出來。

一步一步的實現。

今天先來分解一下排序算法中的一個算法——選擇排序。

為什麽叫選擇排序呢?

一種最簡單的排序算法是這樣的:首先,找到數組中最小的那個元素,其次,將它和數組的第一個元素交換位置(如果第一個元素就是最小的元素那麽它就和自己交換)。再次,在剩下的元素中找到最小的元素,將它與數組的第二個元素交換位置。如此往復,直到將整個數組排序。這種方法叫做選擇排序。

可以發現,選擇排序的關鍵點就是選擇“最小值”。這個名稱,就是這個算法的核心思想。我們先來看一個完整的算法的實現。

        ///選擇排序
	public static void SelectSort0(int[] a){
		int min=0;
		for(int i=0;i<a.length;i++){
			min=i;
			for(int j=i+1;j<a.length;j++){
				if(a[min]>a[j]){
					min=j;
				}
			}
			int tmp=0;
			tmp=a[i];
			a[i]=a[min];
			a[min]=tmp;
		}
		
		for(int i=0;i<a.length;i++){
			System.out.print(a[i] + " ");
		}
	}

這個算法,看完之後比較容易懂,但是不好記。下面我就用分解的方式來對這個算法進行拆解。

第一步:找最小值(索引)

給定一個數組,從中找到第一次出現的最小的值(其索引),這個算法要如何實現呢?

我想用一個循環就可以搞定,代碼如下:

	public static int FindMinIndex(int[] a){
		int min=0;
		for(int i=0;i<a.length;i++){
			if(a[min]>a[i]){
				min=i;
			}
		}
		return min;
	}

選擇排序的思想就是每次遍歷,找到當先序列的最小的索引,和當前的起始索引的元素進行交換。

因此我們需要一個可以自己指定“起始索引”的重載版本:

	public static int FindMinIndex(int[] a,int beginIndex){
		int min=beginIndex;
		for(int i=beginIndex;i<a.length;i++){
			if(a[min]>a[i]){
				min=i;
			}
		}
		return min;
	}

其中,第二個參數,是數組a的起始遍歷的索引。

第二步:交換索引元素

這個很簡單,直接上代碼

	public static void Exchange(int[] a,int i,int j){
		int temp=a[i];
		a[i]=a[j];
		a[j]=temp;
	}

第三步:進行組合

在選擇排序的主方法中,對數組進行一次遍歷。每次遍歷,找到最小的值的元素對應的索引,和當前的起始索引的元素進行交換。遍歷完畢,則數組排序完畢。

	public static void SelectSort(int[] a){
		for(int i=0;i<a.length;i++){
			int beginIndex=i;
			int min = FindMinIndex(a,beginIndex);
			Exchange(a,min,i);
		}
	}

完整代碼如下:

package asen.yang;

public class selectSort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] a={5,1,4,8,3,9,0,2,7,6,1,2,5};
		
		SelectSort(a);
		for(int i=0;i<a.length;i++){
			System.out.print(a[i]+ " ");
		}
	}
	
	
	public static int FindMinIndex(int[] a){
		int min=0;
		for(int i=0;i<a.length;i++){
			if(a[min]>a[i]){
				min=i;
			}
		}
		return min;
	}
	
	public static int FindMinIndex(int[] a,int beginIndex){
		int min=beginIndex;
		for(int i=beginIndex;i<a.length;i++){
			if(a[min]>a[i]){
				min=i;
			}
		}
		return min;
	}
	
	public static void Exchange(int[] a,int i,int j){
		int temp=a[i];
		a[i]=a[j];
		a[j]=temp;
	}
	
	public static void SelectSort(int[] a){
		for(int i=0;i<a.length;i++){
			int beginIndex=i;
			int min = FindMinIndex(a,beginIndex);
			Exchange(a,min,i);
		}
	}
	
	///選擇排序
	public static void SelectSort0(int[] a){
		int min=0;
		for(int i=0;i<a.length;i++){
			min=i;
			for(int j=i+1;j<a.length;j++){
				if(a[min]>a[j]){
					min=j;
				}
			}
			int tmp=0;
			tmp=a[i];
			a[i]=a[min];
			a[min]=tmp;
		}
		
		for(int i=0;i<a.length;i++){
			System.out.print(a[i] + " ");
		}
	}

}

在學習算法時,如果對最終的代碼記不清楚,那可以嘗試使用分解的方式,記住其關鍵點。然後再組合。

而對於向排序這樣的經典算法,幾乎所有的開發語言的類庫中都已經實現了。我們學習的目的,並不僅僅是重復已經實現的東西,更重要的是在學習中,掌握思想。而思想,更多的體現在其中的關鍵點上。因此對算法進行分解,找準關鍵點,理解核心思想,才是學習算法時,所更應該重點關註的角度。

接下來會按照這個思路,進行其他算法的分解。從這個角度,在學習算法的過程中,會有更多的收獲。

用分解的方式學算法001——選擇排序