算法實現之選擇排序及優化

距上一次熱血澎湃看算法已經過去兩年了,如果不是看到馬老師最近開始講算法了估計還會繼續遺忘下去。

先備份一張圖,來源:http://www.mashibing.com(歡迎大家訪問馬老師網站)

 這次來學習選擇排序,顧名思義,選擇排序當然是選擇爲主。舉例說明。

5 6 1 4 3
    ↑

選擇這幾個數中的最小(大)的數:1,放到最前(後)面即和首(尾)位交換

1 6 5 4 3
        ↑

然後再除了1之後選擇最小的數:3,放到第二的位置。

1 3 5 4 6
      ↑  

循環下去,最後得到1 3 4 5 6的數組即可。

用代碼實現:

//選擇排序
void selectSort(int num[],int len)
{
	int i = 0,j = 0;
	int minIndex = 0;
	
	for(i = 0;i < len;i++)
	{
		//假設首部數值爲最小值 
		minIndex = i;
		for(j = i + 1;j < len;j++)
		{
			if(num[j] < num[minIndex])
			{
				//找到最小的值 
				minIndex = j;
			}
		}
		//把最小的值和首部進行交換 
		int temp = num[i];
		num[i] = num[minIndex];
		num[minIndex] = temp;
	}
} 

非常簡單易懂的算法,但是由馬老師的圖可知該算法是不穩定的,什麼叫做不穩定呢?就是兩個相等的值,在排序之後位置可能發生變化,讓我們寫個例程測試一下

struct student
{
	int age;
	char name[20];
};

void main()
{	
	int i = 0,j = 0,minIndex = 0; 
	//注意在初始化的時候,有兩個結構體的age都是4,但是test4 first位置在 test4 last前面 
	struct student all[] = {
		{4,"test4 first"},
		{3,"test3"},
		{4,"test4 last"},
		{2,"test2"},
		{1,"test1"},
	};
	
	for(i = 0;i < 5;i++)
	{
		minIndex = i;
		for(j = i + 1;j < 5;j++)
		{
			if(all[j].age < all[minIndex].age)
			{
				minIndex = j;
			}
		}
		struct student temp = all[minIndex];
		all[minIndex] = all[i];
		all[i] = temp;
	}
	for(i = 0;i < 5;i++)
	{
		printf("%s,",all[i].name);
	}
	printf("\n");
}

運行結果

test1,test2,test3,test4 last,test4 first

很明顯,test4 first和test4 last的位置反了,這就是不穩定造成的結果,舉個例子,A現在銀行存了5萬,B也在銀行存了5萬,理論上查詢存5萬的第一人應該是A,但是經過這個排序算法之後查詢到的卻是B,後面的問題可想而知。

優化:馬老師提示其中一種優化方法可以是一次找到最大值和最小值,把最小值放到前面,最大值放到後面不就把循環次數縮小一半了嗎。

用代碼實現:

//優化選擇排序
void selectSortFindMinAndMax(int num[],int len)
{
	int i = 0,j = 0,k = 0,m = 0;
	int minIndex = 0,maxIndex = 0;
	
	for(i = 0;i < len / 2;i++)
	{
		minIndex = i;
		maxIndex = i;
		for(j = i + 1;j < len - k;j++)
		{
			if(num[j] < num[minIndex])
			{
				//找到最小值 
				minIndex = j;
			}
			if(num[j] > num[maxIndex])
			{
				//找到最大值 
				maxIndex = j;
			}
		}
		//考慮如果最大值就是i下標,如果先交換最小值,則會把最大值位置的數值改變
		//這種情況應該先交換最大值。 
		if((maxIndex == i) && (minIndex != len - k - 1))
		{
			swap(num,len - k - 1,maxIndex);
			swap(num,i,minIndex);
		}
		//考慮如果最大值是i下標,最小值是循環尾,則只用交換一次即可。 
		else if((maxIndex == i) && (minIndex == len - k - 1))
		{
			swap(num,maxIndex,minIndex);
		}
		//其餘情況先交換最小值,再交換最大值 
		else
		{
			swap(num,i,minIndex);
			swap(num,len - k - 1,maxIndex);
		}
		//循環一次之後,循環尾向前移 
		k++;
	}
}

兩種方法的循環次數以及時間比較(數組大小10000,有rand()隨機產生):

系統函數0.001000ms,普通選擇0.111000ms循環49995000次,優化選擇0.083000ms循環25000000次
系統函數0.002000ms,普通選擇0.115000ms循環49995000次,優化選擇0.071000ms循環25000000次
系統函數0.002000ms,普通選擇0.112000ms循環49995000次,優化選擇0.077000ms循環25000000次
系統函數0.002000ms,普通選擇0.106000ms循環49995000次,優化選擇0.081000ms循環25000000次
系統函數0.001000ms,普通選擇0.111000ms循環49995000次,優化選擇0.077000ms循環25000000次
系統函數0.001000ms,普通選擇0.119000ms循環49995000次,優化選擇0.093000ms循環25000000次
系統函數0.002000ms,普通選擇0.113000ms循環49995000次,優化選擇0.088000ms循環25000000次
系統函數0.001000ms,普通選擇0.110000ms循環49995000次,優化選擇0.074000ms循環25000000次
系統函數0.001000ms,普通選擇0.112000ms循環49995000次,優化選擇0.075000ms循環25000000次
系統函數0.001000ms,普通選擇0.114000ms循環49995000次,優化選擇0.076000ms循環25000000次

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章