1. 程式人生 > >演算法分析之蠻力法(暴力法)

演算法分析之蠻力法(暴力法)

目錄

1, 蠻力法的概述及定義

蠻力法——簡單說是一種簡單直接的演算法設計策略,也叫作暴力法,列舉法或者窮舉法,蠻力法解決問題常常簡單粗暴,常常基於問題的描述和所涉及的概念,定義直接求解,逐一列舉並且處理問題所涉及的所有情形,然後得到問題的答案。在求解問題的過程中往往依據迴圈結構來實現。

1.1,求解問題所要依據的步驟

(1)確定掃描和列舉變數。

(2)確定列舉變數的範圍,設定相應的迴圈。

(3)根據問題的描述確定約束的條件,以便找到合理 的解。

2,例題演練

2.1百雞百錢問題

為題描述:數學家張丘建提出百雞百錢問題,今有雞翁一,值錢五,雞母一,值錢三,雞雛三,值錢一。百錢買百雞,問雞翁,雞母,雞雛各幾何?

問題分析:設雞翁,雞母,雞雛分別為x,y,z,題意給出一百錢要買百雞,如果全買公雞最多買20只,顯然x在0—20之間,同理y的取值在0-33之間,所以根據分析,不難用列舉法求出問題的所有符合情況的解。

void HundredFowlsMoney()
{
	int z = 0;
	for (int x= 0; x < 20; x++)//雞翁的數量變化範圍
	{
		for (int y = 0; y < 33; y++)//雞母的數量變化範圍
		{
			z = 100 - x - y;
			if (z % 3 == 0 && 5 * x + 3 * y + z / 3 == 100)//雞雛z受x,y的制約
			cout << "雞翁:" << x << endl;
			cout << "雞母:" << y << endl;
			cout << "雞雛:" << z << endl;
		}
	}
}

2.2 排序問題

2.2.1 選擇排序

基本思想:對有n個元素的序列進行n-1趟排序,第一趟排序對序列進行從頭到尾掃描,找到最小的元素與第一個元素交換;第二趟排序從第二個元素起開始掃描,依然找到最小元素和第二個交換,;一般來說,第i趟排序從序列的第i個元素起到序列尾的n-i+1個元素中找到最小元素,然後和第i個元素交換順序,按照上述方法完成對n個元素的排序。

//選擇排序
void SelectSort(int arr[], int n)//對數組裡面的n個元素進行排序
{
	int min;
	int temp = 0;
	for (int i = 0; i <= n - 2; i++) {
		min = i;//在此處假設第一個元素最小,記住其下標
		for (int j = i + 1; j < n; j++)
		{
			if (arr[j] < arr[min])
				min = j;//在這裡如果找到比當前元素更小的,就記住其下標
		}
		temp = arr[i];//在這裡進行交換,把第i個元素和搜尋到的最小元素交換,min永遠儲存
		arr[i] = arr[min];//最小元素的下標
		arr[min] = temp;
	}
}

在這裡方便大家理解,我以7個元素陣列的例子來模擬一遍選擇排序的演算法。

初始序列:80,18,72,95,29,45,12

第一趟排序:|80,18,72,95,29,45,12   i=0:min最後的6,交換二者

第二趟排序:12,|18,72,95,29,45,80   i=1:min最後得1,不交換

第三趟排序:12,18,|72,95,29,45,80  i=2:min最後得4,交換二者

第四趟排序:12,18,29, |95,72,45,80  i=3:min最後的5,交換二者

第五趟排序:12,18,29,45,|72,95,80   i=4:min最後得4,不交換

第六趟排序:12,18,29,45,72,|95,80  i=5,min最後得6,交換二者

最後一趟排序:12,18,29,45,72,80,|95   排序結束

以上標紅色的數字是每趟需要和第i個元素交換的數字,在排序過程中,豎線左側是已經排好的元素,每次從豎線右側第一個元素開始掃描,直到掃描完最後一個元素,找到本輪的最小元素,將最小元素和第i和元素交換位置即可,經過n-1趟完成排序,n代表輸入元素規模。

2.2.2 氣泡排序

氣泡排序基本思想:對具有n個元素的序列也進行n-1趟排序。第一趟排序對序列進行從頭到尾進行相鄰元素的比較,如果是逆序(即大在前小在後),則進行相鄰元素之間的交換,這樣經過一趟排序後,最大元素沉到了陣列的第n個位置,第二趟排序對陣列進行從頭到n-1個元素進行相鄰元素之間的比較,如果逆序就交換,這樣經過第二趟排序,次大元素就沉到陣列的倒數第二個位置,第i趟排序從陣列的頭到陣列的第n-i+1個元素進行相鄰之間的比較,,依次做同樣的操作,一趟排序後,第i大的元素就落在了第n-i+1的位置上,經過n-1趟排序,即可完成對陣列的排序操作。

//氣泡排序,遞增排序
void BubbleSort(int arr[], int n)
{
	int temp = 0;
	for (int i = 0; i < n - 1; i++) {
		for (int j = 0; j <= n - 2 - i; j++)
		{
			if (arr[j + 1] < arr[j])//每一次都比較相鄰的兩個元素
			{
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
}
//冒泡演算法改進演算法
加入我們輸入的序列本身就有序,那麼經過一次掃描後,發現沒有進行一次元素交換,說明序列是有序的,就直接跳出迴圈,所以在這裡我們設定一個flag標誌位
void BubbleSort(int arr[], int n)
{
	int temp = 0;
	int flag = true;//在這裡設定標誌位
	for (int i = 0; i < n - 1&&flag; i++) {//判斷是否進行了交換,如果沒交換說明序列有                                
		for (int j = 0; j <= n - 2 - i; j++)//序,直接就退出迴圈
		{
			if (arr[j + 1] < arr[j])
			{
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
				flag = false;
			}
		}
	}
}

在這裡寫出對7個元素的陣列進行排序的模擬過程,以方便大家理解。

初始序列:80,18,72,95,29,45,12

第一趟排序:18,72,80,29,45,12,|95  i=0;最大值95就位

第二趟排序:18,72,29,45,12,|80,95  i=1:最大值80就位

第三趟排序:18,29,45,12,|72,80,95  i=2:最大值72就位

第四趟排序:18,29,12,|45,72,80,95  i=3:最大值45就位

第五趟排序:18,12,|29,45,72,80,95  i=4:最大值29就位

第六躺排序:12,|18,29,45,72,80,95  i=5:最大值18就位,n-1趟排序結束。

紅色標明的數字是每趟選出的最大值放到的位置。在演算法執行過程中,豎線右側是已經排好序的元素,掃描時從左端開始,每次比較當前與其右側的元素,如果逆序就交換,經過n-1趟完成排序,n代表輸入元素規模。

2.3 查詢問題

順序查詢演算法:字串匹配,在這裡待查詢的字串稱為文字,與其進行部分匹配的字串稱為模式,字串匹配問題的蠻力法求解是將模式對準文字的開始位置,從左到右逐一查詢對應的字元,如果相同,就查詢下一個字元;如果不同,則將模式的起始位置重新設定為開始的位置(相當於對應的匹配位置又重新開始),如果成功找到匹配位置,則返回最左端字元在文字中的位置。如果匹配的位置距離文字最後 字元長度小於模式串的長度,則返回匹配失敗。例如第一個文字長度為n,模式串的長度為m,則在文字中可能匹配成功的位置在0至n-m,應為在n-m的右側字串距離文字最後一個字元的長度已經不足m,匹配一定不成功。所以演算法實現如下:

//W_arr[]表示文字串,M_arr[]表示模式串,w_num, m_num分別表示文字串和模式串的長度
int BruteForceIndex(int W_arr[], int M_arr[], int w_num, int m_num)
{
	for (int i=0; i < w_num - m_num; i++)
	{
		int j = 0;
		while (j < m_num&&W_arr[i+j] == M_arr[j])//判斷模式串是否匹配成功
		{
			j++;
			if (j == m_num)
				return i;//如果匹配成功,返回模式串在文字中的第一個字元下標
		}
	}
}
p a t c h n o t a p p l i e d
a p p
a p p
a p p
a p p
a p p
a p p
a p p
a p p
a p p
a p p
a p p

以上為字串app的模擬執行過程,加粗的字元表示每次匹配匹配不成功的字元,直到最後一次匹配完成,返回app在文字串中匹配成功第一個字元的位置。

當然還有很多蠻力法的例子,比如幾何問題,凸包問題等等,在這裡只是簡單論述一下蠻力法求解問題的方法,以便我們拿到一個問題後,在不知道什麼方法最合適的情況下,儘快用暴力求解法解決問題,本篇博文還會持續更新,歡迎大家指出不足,謝謝大家。