演算法分析之蠻力法(暴力法)
目錄
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在文字串中匹配成功第一個字元的位置。
當然還有很多蠻力法的例子,比如幾何問題,凸包問題等等,在這裡只是簡單論述一下蠻力法求解問題的方法,以便我們拿到一個問題後,在不知道什麼方法最合適的情況下,儘快用暴力求解法解決問題,本篇博文還會持續更新,歡迎大家指出不足,謝謝大家。