五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

基于linux的C++學(xué)習(xí)筆記4(算法 示例 優(yōu)化)

2020-02-16 21:30 作者:技術(shù)龍的傳人  | 我要投稿

算法:解決問題的方法和步驟

設(shè)計算法的目的:給出解決問題的邏輯描述,根據(jù)算法描述進(jìn)行實際編程


算法特征:有窮性、確定性、輸入、輸出、有效性

有窮性——算法在每種情況下都可以在有限步后終止

確定性——算法步驟的順序和內(nèi)容沒有二義性

輸入——算法有零個或多個輸入

輸出——算個發(fā)至少具有一個輸出

有效性——所有操作具有明確的含義,并在有限時間內(nèi)完成

正確性不是算法的特征,算法的正確性數(shù)學(xué)證明

算法示例一:幻方(3*3)

? ? ? ? ? 9? ? ? ?2

?8? ? ? ?1?? ? ? 6?? ? ? ?8

?3? ? ?? 5 ? ? ? 7?? ? ? ?3

?4? ? ? ?9?? ? ? 2? ?

省略了格子

找出規(guī)律,編寫步驟:

步驟一:把1寫在第一行中間一格

步驟二:在該格右上方的那一格寫入下一個自然數(shù)(若該數(shù)超出3*3幻方范圍,將該數(shù)寫在其所在的那一排或列的另一端格子中,即相當(dāng)于認(rèn)為幻方外圍仍然包含了同樣的幻方,而該數(shù)卸載外圍幻方的同樣位置;每寫完三個數(shù),將第四個樹寫在第三個數(shù)下面格子中)

步驟三:重復(fù)步驟二,直到所有格子均填滿


算法示例二:查英文單詞

步驟一:翻開詞典任意一頁

步驟二:若所查的詞匯按字母排列順序在本頁第一個單詞之前,則往前翻開任意一頁,重復(fù)步驟二;若所查單詞在本頁最后一個單詞之后,則往后翻開任意一頁,重復(fù)步驟二

步驟三:若上述兩個條件都不滿足,則該單詞要么在本頁上,要么詞典中不存在(依次比較本頁單詞,或者查出該單詞,或者得到該單詞查不到的結(jié)論)


算法描述:偽代碼、流程圖

偽代碼——混合自然語言與計算機語言、數(shù)學(xué)語言的算法描述方法

優(yōu)點:方便,容易表達(dá)設(shè)計者思想,清洗描述算法流程,便于修改

缺點:不美觀,復(fù)雜算法不容易理解

順序結(jié)構(gòu)、分支結(jié)構(gòu)(if??else)、循環(huán)結(jié)構(gòu)(for?while)

流程圖(程序框圖)——使用圖形表示算法執(zhí)行邏輯

優(yōu)點:美觀,算法表達(dá)清晰

缺點:繪制復(fù)雜,不易修改,占用過多篇幅

處理(流程圖中的一個處理或者步驟)
預(yù)處理(決定下一個步驟的一個子進(jìn)程。可以有多種結(jié)果,但往往只有兩個 – yes和no)
判斷(對一個條件進(jìn)行判斷抉擇??梢杂卸喾N結(jié)果,但往往只有兩個 – 是的,沒有)
起點和終點(一個流程開始和結(jié)束)
數(shù)據(jù)形狀(指示信息進(jìn)程外,或離開的過程)

。

延遲形狀(沒有活動,做一個等待期。在流程圖中,延誤往往是重要的,因為它們可能會導(dǎo)致增加產(chǎn)品的成本,或簡單地推遲其生產(chǎn))
數(shù)據(jù)庫形狀(使用這種形狀的結(jié)果被儲存在信息的步驟)
離頁引用(下一個或上一個步驟是別的地方上的流程圖。它在大型流程圖特別有用)
文檔(一個文件和資料集)

算法設(shè)計與實現(xiàn)

構(gòu)造算法解決問題

按照自頂向下、逐步求精的方式進(jìn)行

使用程序設(shè)計語言設(shè)計語言編程實現(xiàn)

典型示例:

素數(shù)判定問題——判定給定的某個自然數(shù)n(大于2是否為素數(shù))

算法邏輯

????輸入:大于2的正整數(shù)n

????輸出:該數(shù)是否為素數(shù),若為素數(shù)返回true,否則返回false

????步驟一:設(shè)除數(shù)i為2

????步驟二:判斷除數(shù)i是否已為n,若為真返回true,否則繼續(xù)

????步驟三:判斷n%i是否為0,若為0返回false,否則繼續(xù)

????步驟四:將除數(shù)i遞增,重復(fù)步驟二

第一版

bool?IsPrime(unsigned int n){

????unsigned int i = 2;

????while(i < n){

????????if(n%i == 0)? ? ????????return?false;

????????i++;

????}

????return true;

}

第二版(優(yōu)化用平方根以內(nèi)數(shù)做除數(shù))

bool IsPrime(unsigned int n){

????unsigned int i = 2;

????while(i <= (unsigned int)sqrt(n)){? ? ? ? ?//sqrt為標(biāo)準(zhǔn)庫中的求平方根函數(shù),返回值為浮點數(shù)

????????if(n%i == 0)? ? return false;

????????i++;

????}

????return true;

}

第三版(優(yōu)化首先判斷是否是偶數(shù))

bool IsPrime(unsigned int n){

????unsigned int i?= 3;

????if(n%2 == 0)? ? ? ?return false;? ? ? ? ? ? ? //是偶數(shù)也就是合數(shù)

????while(i <= (unsigned int)sqrt(n)){? ? ? ? ?//sqrt為標(biāo)準(zhǔn)庫中的求平方根函數(shù),返回值為浮點數(shù)

????????if(n%i == 0)? ? return false;

????????i++;

????}

????return true;

}

第四版(優(yōu)化防止平方根計算浮點數(shù)帶來的誤差導(dǎo)致錯誤,如:121的平方根被計算成10.999999強轉(zhuǎn)unsigned?int為10)

bool IsPrime(unsigned int n){

????unsigned int i?= 3;

????if(n%2 == 0)? ? ? ?return false;? ? ? ? ? ? ? //是偶數(shù)也就是合數(shù)

????while(i <=?(unsigned int)sqrt(n) + 1){? ? ? ? ?//sqrt為標(biāo)準(zhǔn)庫中的求平方根函數(shù),返回值為浮點數(shù)

????????if(n%i == 0)? ? return false;

????????i++;

????}

????return true;

}

第五版(優(yōu)化防止求平方根操作在while循環(huán)中重復(fù)執(zhí)行)

bool IsPrime(unsigned int n){

????unsigned int i?= 3, t = (unsigned int)sqrt(n)?+?1;

????if(n%2 == 0)? ? ? ?return false;??? ? ? ? ? ? //是偶數(shù)也就是合數(shù)

????while(i?<= t){? ? ? ? ?//sqrt為標(biāo)準(zhǔn)庫中的求平方根函數(shù),返回值為浮點數(shù)

????????if(n%i == 0)? ? return false;

????????i += 2;

????}

????return true;

}

算法選擇的權(quán)衡指標(biāo)

正確性:算法是否完全正確

效率:在某些場合,對程序效率的追求具有重要意義

可理解性:算法是否容易理解,也是必須要考慮的

算法評估:衡量算法的好壞,主要是效率

最大公約數(shù)問題——求兩個整數(shù)x與y的最大公約數(shù)

第一版(窮舉法)

unsigned int gcd(unsigned int x, unsigned int y){

????unsigned int t;

????t = x<y?x:y;

????while(x%t != 0 || y%t != 0)? ? ?t--;

????return t;

}

第二版(歐式算法)

輸入:正整數(shù)x、y

輸出:最大公約數(shù)

步驟一:x整除以y,記余數(shù)為r

步驟二:若r為0,則最大公約數(shù)即為y,算法結(jié)束

步驟三:否則將y作為新x,將r作為新y,重復(fù)上述操作

unsigned int gcd(unsigned int x, unsigned int y){

????unsigned int t;

????while(true)

????{

????????r = x%y;

????????if(r == 0)? ? ? ? ? return y;

????????x = y;

????????y = r;?

????}

}

遞歸算法

遞推公式:數(shù)學(xué)上很常見,階乘函數(shù)(1!=1,n!=n*(n-1)?。㈧巢瞧鯏?shù)列(f(1)=f(2)=1,f(n)=f(n-1)+f(n-2))

遞推函數(shù)一定是分段函數(shù),具有初始表達(dá)式

遞推函數(shù)的計算邏輯:逐步簡化問題規(guī)模

遞歸的工作步驟

????遞推過程:逐步分解問題,使其更簡單

????回歸過程:根據(jù)簡單情形組裝最后的答案

階乘函數(shù)

使用循環(huán)實現(xiàn)

unsigned int GetFactorial(unsigned int n){

????unsigned int result? = 1, i = 0;

????while(++i <= n)? ? ?result *= i;

????return result;

}

使用遞歸實現(xiàn)

unsigned int GetFactorial(unsigned int n){

????unsigned int?result;

????if(1 ==?n)? ? ?result =?1;

????else? ? ? ? ? ? ?result = n*GetFactorial(n-1);

????return result;

}

斐波那契數(shù)列函數(shù)

使用循環(huán)實現(xiàn)

unsigned?int GetFibonacci(unsigned int n){

????unsigned int i, f1, f2, f3;

????if(2 == n || 1 == n)? ? ? ?return 1;

????f2 = 1;f1 = 1;

????for(i = 3; i <= n; i++){

????????f3 = f2 + f1; f1 = f2; f2 = f3;

????}

????return f3;

}

使用遞歸實現(xiàn)

unsigned?int GetFibonacci(unsigned int n){

????if(2 == n || 1 == n)? ? ? ?return 1;

? ??else? ? ? ? ? ? ? ? ? ? ? ? ? ? ?return GetFibonacci(n-1) +?GetFibonacci(n-2);

}

循環(huán)和遞歸的比較:

????循環(huán)使用顯式的循環(huán)結(jié)構(gòu)重復(fù)執(zhí)行代碼段,遞歸使用重復(fù)的函數(shù)調(diào)用執(zhí)行代碼段

????循環(huán)在滿足其終止條件時終止執(zhí)行,而遞歸則在問題簡化到最簡單情形時終止執(zhí)行

????循環(huán)的重復(fù)是在當(dāng)前迭代執(zhí)行結(jié)束時進(jìn)行,遞歸的重復(fù)則是在遇到對同名函數(shù)的調(diào)用時進(jìn)行

????循環(huán)和遞歸都可能隱藏程序錯誤,循環(huán)的條件測試可能永遠(yuǎn)為真,遞歸可能永遠(yuǎn)退化不到最簡單情形

????理論上任何遞歸程序都能使用循環(huán)迭代的辦法解決(遞歸函數(shù)的代碼短小精悍,掌握遞歸的思考方法,遞歸程序更容易理解)

漢諾塔問題——假設(shè)有三個分別命名為X、Y和Z的塔座,在塔座X上插有n個直徑大小不同、依小到大分別編號為1,2,3......,n的圓盤,要求將塔座X上的n歌圓盤移動到塔座Z上并按相同順序疊放,圓盤移動時必須遵循的規(guī)則:

????每次只能移動一個圓盤;

????圓盤可以插在X、Y、Z中的任意一個塔座上;

????任何時刻都不能將較大的圓盤壓在較小的圓盤上;

問題分析:

????是否存在簡單情形,問題很容易解決

????是否將原始問題分解成性質(zhì)相同但規(guī)模較小的子問題,且新問題的解答對原始問題有關(guān)鍵意義

解決方案(數(shù)學(xué)歸納法)

????只有一個圓盤是最簡單的情形

????對于n-1,考慮n-1個圓盤,若將n-1個圓盤移動到某個塔座上,則可移動第n個圓盤

????策略:先將n-1個圓盤移動到塔座Y上,然后將第n個圓盤移動到Z上,最后將n-1個圓盤從Y上移動到Z上

偽代碼

void MoveHanoi(unsigned int n, HANOI from, HANOI tmp, HANOI to)

{

????if(1 == n)????將一個圓盤從form移動到to

????else{

????????將n-1個圓盤從from以to為中轉(zhuǎn)移動到tmp

????????將圓盤n從from移動到to

????????將n-1個圓盤從tmp以from為中轉(zhuǎn)移動到to

????}

}


程序代碼

#include<iostream>

using namespace std;

/*?枚舉類型HANOI,?分別表示三個圓柱代號?*/

unsigned int GetInteger();

void MoveHanoi(unsigned int n, HANOI from, HANOI tmp, HANOI to);

char ConverHanoiToChar(HANOI x);

void MovePlate(unsigned int n, HANOI from, HANOI to);

int main(){

????unsigned int n;

????n =?GetInteger();

????MoveHanoi(n, X, Y, Z);

????return 0;

}

unsigned int?GetInteger(){//獲取輸入值

????unsigned int t;

????cout << "Input number of plates:";

????cin >> t;

????return t;

}

void?MoveHanoi(unsigned int n, HANOI from, HANOI tmp, HANOI to){

????if(1 == n)????MovePlate(n, from , to);

????else{

????????MoveHanoi(n-1, from, to, tmp);

????????MovePlate(n, from, to);

????????MoveHanoi(n-1, tmp, from, to);

????}

}

char ConverHanoiToChar(HANOI?x){//將枚舉文字轉(zhuǎn)換成字符

????switch(x){

????????case X:return 'X';

? ? ????case Y:return 'Y';

? ? ????case Z:return 'Z';

? ? ? ? default:return '\0';

????}

}

void?MovePlate(unsigned int n, HANOI from,?HANOI to){

????char fc, tc;

????fc = CovertHanoiToChar(from);

? ??tc = CovertHanoiToChar(to);

????cout << n << ":" << fc << "-->" << tc <<endl;

}

遞歸信任

遞歸實現(xiàn)是否檢查了最簡單的情形

????在嘗試將問題分解成子問題前,首先檢查問題是否已足夠簡單

????在大多數(shù)情況下,遞歸函數(shù)以if開頭

????如果不是這樣,仔細(xì)檢查源代碼

是否解決了最簡單情形

????大量遞歸錯誤是由沒有正確解決最簡單情形導(dǎo)致的

????最簡單情形不能調(diào)用遞歸

遞歸分解是否使問題更簡單

????只有分解出子問題更簡單,遞歸才能正確工作,否則將形成無限遞歸,算法無法終止

問題簡化過程是否能夠確實回歸最簡單情形,還是遺漏了某些情況

????如漢諾塔問題需要調(diào)用兩次遞歸過程,程序中如果遺漏了任意一個都會導(dǎo)致錯誤

子問題是否與原始問題完全一致

????如果遞歸過程改變了問題實質(zhì),則整個過程肯定會得到錯誤結(jié)果

使用遞歸信任時,子問題的解是否正確組裝為原始問題的解

????將子問題的解正確組裝以形成原始問題的解也是必不可少的步驟

容錯:允許錯誤的發(fā)生

錯誤的處理

????很少見的特殊情況或普通錯誤:忽略該錯誤不對程序運行結(jié)果產(chǎn)生影響

????用戶輸入錯誤:通知用戶錯誤性質(zhì),提醒用戶更正輸入

????致命錯誤:通知用戶錯誤的性質(zhì),停止執(zhí)行

典型容錯手段

????數(shù)據(jù)有效性檢查

????程序流程的提前終止

數(shù)據(jù)有效性檢查示例:

void GetUserInput(){

????獲取用戶輸入的數(shù)據(jù)

????while(用戶輸入的數(shù)據(jù)無效){

????????通知用戶輸入數(shù)據(jù)有誤,提醒用戶重新輸入數(shù)據(jù)

????????重新獲取用戶輸入數(shù)據(jù)

????}

}

素數(shù)判定函數(shù)第六版(添加參數(shù)檢查及異常處理)

const int failed_in_testing_primality = 1;

bool IsPrime(unsigned int n){

????unsigned int i = 3, t = (unsigned int)sqrt(n)+1;

????if(1 =>?n){//越界處理,提示錯誤信息并返回錯誤碼

????????cout << "IsPrime:Failed in testing the primality of" << n << endl;

????????exit(failed_in_testing_primality);

????}

? ? if(n?== 2)????return true;//2為素數(shù)

????if(n%2 == 0)????return false;

????while( i <= t){

????????if(n%i == 0)? return false;

????????i += 2;

????}

????return true;

}

算法復(fù)雜度

引入算法復(fù)雜度的目的——度量算法的效率和性能

大O表達(dá)式

????算法效率與性能的近似表示(定性描述)

????算法執(zhí)行時間與問題規(guī)模的關(guān)系

表示原則

????忽略所有對變化趨勢影響較小的項,例如多項式忽略高階項之外的所有項

????忽略所有與問題規(guī)模無關(guān)的常數(shù),例如多項式的系數(shù)

O(1):常數(shù)級,表示算法執(zhí)行時間與問題規(guī)模無關(guān)

O(log(n)):對數(shù)級,表示算法執(zhí)行時間與問題規(guī)模的對數(shù)成正比

O(sprt(n)):平方根級,表示算法執(zhí)行時間與問題規(guī)模的平方根成正比

O(n):線性級,表示算法執(zhí)行時間與問題規(guī)模成正比

O(n*log(n)):n*log(n)級,表示算法執(zhí)行時間與問題規(guī)模的n*log(n)成正比

O(n2):平方級,表示算法執(zhí)行時間與問題規(guī)模的平方成正比

......

算法復(fù)雜度估計

for(i =?0; i < n; i++)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //O(n)

????;

for(i?=?0; i < n; i++)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //O(n2)

???for(j?=?0; j?< n; j++)

?????????;

for(i?=?0; i < n; i++)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //O(n2)

???for(j?=?i;?j?<?n;?j++)

?????????;


基于linux的C++學(xué)習(xí)筆記4(算法 示例 優(yōu)化)的評論 (共 條)

分享到微博請遵守國家法律
肇东市| 深州市| 辉南县| 静海县| 万年县| 兴海县| 长兴县| 云龙县| 贡觉县| 玉门市| 观塘区| 裕民县| 合作市| 安龙县| 平果县| 淳安县| 岑溪市| 吉首市| 南通市| 长垣县| 休宁县| 西平县| 宿松县| 宁德市| 潮州市| 兰溪市| 九江县| 县级市| 灯塔市| 玉屏| 长沙市| 四平市| 三门县| 永春县| 天门市| 普宁市| 永年县| 兴山县| 两当县| 永嘉县| 北京市|