第四百一十四节,python常用算法学习
本節內容
1.算法定義?
算法(Algorithm)是指解題方案的準確而完整的描述,是一系列解決問題的清晰指令,算法代表著用系統的方法描述解決問題的策略機制。也就是說,能夠對一定規范的輸入,在有限時間內獲得所要求的輸出。如果一個算法有缺陷,或不適合于某個問題,執行這個算法將不會解決這個問題。不同的算法可能用不同的時間、空間或效率來完成同樣的任務。一個算法的優劣可以用空間復雜度與時間復雜度來衡量。
一個算法應該具有以下七個重要的特征:
①有窮性(Finiteness):算法的有窮性是指算法必須能在執行有限個步驟之后終止;
②確切性(Definiteness):算法的每一步驟必須有確切的定義;
③輸入項(Input):一個算法有0個或多個輸入,以刻畫運算對象的初始情況,所謂0個輸 ? ? 入是指算法本身定出了初始條件;
④輸出項(Output):一個算法有一個或多個輸出,以反映對輸入數據加工后的結果。沒 ? ? ? 有輸出的算法是毫無意義的;
⑤可行性(Effectiveness):算法中執行的任何計算步驟都是可以被分解為基本的可執行 ? ? ? 的操作步,即每個計算步都可以在有限時間內完成(也稱之為有效性);
⑥高效性(High efficiency):執行速度快,占用資源少;
⑦健壯性(Robustness):對數據響應正確。
?
叫賣錄音網
錄音網站
?
2. 時間復雜度
計算機科學中,算法的時間復雜度是一個函數,它定量描述了該算法的運行時間,時間復雜度常用大O符號(大O符號(Big O notation)是用于描述函數漸進行為的數學符號。更確切地說,它是用另一個(通常更簡單的)函數來描述一個函數數量級的漸近上界。在數學中,它一般用來刻畫被截斷的無窮級數尤其是漸近級數的剩余項;在計算機科學中,它在分析算法復雜性的方面非常有用。)表述,使用這種方式時,時間復雜度可被稱為是漸近的,它考察當輸入值大小趨近無窮時的情況。
大O,簡而言之可以認為它的含義是“order of”(大約是)。
無窮大漸近
大O符號在分析算法效率的時候非常有用。舉個例子,解決一個規模為 n 的問題所花費的時間(或者所需步驟的數目)可以被求得:T(n) = 4n^2 - 2n + 2。
當 n 增大時,n^2; 項將開始占主導地位,而其他各項可以被忽略——舉例說明:當 n = 500,4n^2; 項是 2n 項的1000倍大,因此在大多數場合下,省略后者對表達式的值的影響將是可以忽略不計的。
?
常數階O(1)
常數又稱定數,是指一個數值不變的常量,與之相反的是變量
為什么下面算法的時間復雜度不是O(3),而是O(1)。
| 1 2 3 | int sum = 0,n = 100; /*執行一次*/? sum = (1+n)*n/2; /*執行一次*/? printf("%d", sum); /*行次*/ |
這個算法的運行次數函數是f(n)=3。根據我們推導大O階的方法,第一步就是把常數項3改為1。在保留最高階項時發現,它根本沒有最高階項,所以這個算法的時間復雜度為O(1)。
另外,我們試想一下,如果這個算法當中的語句sum=(1+n)*n/2有10句,即:
| 1 2 3 4 5 6 7 8 9 10 11 12 | int sum = 0, n = 100; /*執行1次*/? sum = (1+n)*n/2; /*執行第1次*/? sum = (1+n)*n/2; /*執行第2次*/? sum = (1+n)*n/2; /*執行第3次*/? sum = (1+n)*n/2; /*執行第4次*/? sum = (1+n)*n/2; /*執行第5次*/? sum = (1+n)*n/2; /*執行第6次*/? sum = (1+n)*n/2; /*執行第7次*/? sum = (1+n)*n/2; /*執行第8次*/? sum = (1+n)*n/2; /*執行第9次*/? sum = (1+n)*n/2; /*執行第10次*/? printf("%d",sum); /*執行1次*/ |
事實上無論n為多少,上面的兩段代碼就是3次和12次執行的差異。這種與問題的大小無關(n的多少),執行時間恒定的算法,我們稱之為具有O(1)的時間復雜度,又叫常數階。
注意:不管這個常數是多少,我們都記作O(1),而不能是O(3)、O(12)等其他任何數字,這是初學者常常犯的錯誤。
?
?O(n【時間規模,也可以理解為運行次數】),當運算里沒有最高階項(也就是次方)時,時間規模就是1,所以為o(1),
如果運算里包含了最高階項(也就是次方)時,且次方數不為1時,時間規模就是最高階項(也就是次方數),如o(3),
?
推導大O階方法
1.用常數1取代運行時間中的所有加法常數
2.在修改后的運行次數函數中,只保留最高階項
3.如果最高階項存在且不是1,則去除與這個項相乘的常數
對數階O(log2n)
對數
如果a的x次方等于N(a>0,且a不等于1),那么數x叫做以a為底N的對數(logarithm),記作x=logaN, 。其中,a叫做對數的底數,N叫做真數。
5^2 = 25 , 記作 2= log5 25?
對數是一種運算,與指數是互逆的運算。例如
① 3^2=9 <==> 2=log<3>9;
② 4^(3/2)=8 <==> 3/2=log<4>8;
③ 10^n=35 <==> n=lg35。為了使用方便,人們逐漸把以10為底的常用對數記作lgN
?
對數階
| 1 2 3 4 5 6 7 8 9 | int count = 1; while (count < n) {??? count = count * 2; /* 時間復雜度為O(1)的程序步驟序列 */ } |
由于每次count乘以2之后,就距離n更近了一分。
也就是說,有多少個2相乘后大于n,則會退出循環。
由2^x=n得到x=log2n。所以這個循環的時間復雜度為O(logn)。
?
線性階O(n)
執行時間隨問題規模增長呈正比例增長
| 1 2 3 4 5 | data = [ 8,3,67,77,78,22,6,3,88,21,2] find_num = 22 for i in data: ????if i == 22: ????????print("find",find_num,i ) |
?
線性對數階O(nlog2n)
?
?
平方階O(n^2)
| 1 2 3 4 | for i in range(100): ????for k in range(100): ????????print(i,k) |
立方階O(n^3)
k次方階O(n^k),
指數階O(2^n)。
隨著問題規模n的不斷增大,上述時間復雜度不斷增大,算法的執行效率越低。
?
?
一、計算方法 1.一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。并且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。 一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。 2.一般情況下,算法的基本操作重復執行的次數是模塊n的某一個函數f(n),因此,算法的時間復雜度記做:T(n)=O(f(n))。隨著模塊n的增大,算法執行的時間的增長率和f(n)的增長率成正比,所以f(n)越小,算法的時間復雜度越低,算法的效率越高。 在計算時間復雜度的時候,先找出算法的基本操作,然后根據相應的各語句確定它的執行次數,再找出T(n)的同數量級(它的同數量級有以下:1,Log2n ,n ,nLog2n ,n的平方,n的三次方,2的n次方,n!),找出后,f(n)=該數量級,若T(n)/f(n)求極限可得到一常數c,則時間復雜度T(n)=O(f(n))。 3.常見的時間復雜度 按數量級遞增排列,常見的時間復雜度有: 常數階O(1), 對數階O(log2n), 線性階O(n), 線性對數階O(nlog2n), 平方階O(n^2), 立方階O(n^3),..., k次方階O(n^k), 指數階O(2^n) 。 其中, 1.O(n),O(n^2), 立方階O(n^3),..., k次方階O(n^k) 為多項式階時間復雜度,分別稱為一階時間復雜度,二階時間復雜度。。。。 2.O(2^n),指數階時間復雜度,該種不實用 3.對數階O(log2n), 線性對數階O(nlog2n),除了常數階以外,該種效率最高 例:算法:for(i=1;i<=n;++i){for(j=1;j<=n;++j){c[ i ][ j ]=0; //該步驟屬于基本操作 執行次數:n^2 for(k=1;k<=n;++k)c[ i ][ j ]+=a[ i ][ k ]*b[ k ][ j ]; //該步驟屬于基本操作 執行次數:n^3}}則有 T(n)= n^2+n^3,根據上面括號里的同數量級,我們可以確定 n^3為T(n)的同數量級則有f(n)= n^3,然后根據T(n)/f(n)求極限可得到常數c則該算法的 時間復雜度:T(n)=O(n^3) 四、?
| 定義:如果一個問題的規模是n,解這一問題的某一算法所需要的時間為T(n),它是n的某一函數 T(n)稱為這一算法的“時間復雜性”。 當輸入量n逐漸加大時,時間復雜性的極限情形稱為算法的“漸近時間復雜性”。 我們常用大O表示法表示時間復雜性,注意它是某一個算法的時間復雜性。大O表示只是說有上界,由定義如果f(n)=O(n),那顯然成立f(n)=O(n^2),它給你一個上界,但并不是上確界,但人們在表示的時候一般都習慣表示前者。 此外,一個問題本身也有它的復雜性,如果某個算法的復雜性到達了這個問題復雜性的下界,那就稱這樣的算法是最佳算法。 “大O記法”:在這種描述中使用的基本參數是 n,即問題實例的規模,把復雜性或運行時間表達為n的函數。這里的“O”表示量級 (order),比如說“二分檢索是 O(logn)的”,也就是說它需要“通過logn量級的步驟去檢索一個規模為n的數組”記法 O ( f(n) )表示當 n增大時,運行時間至多將以正比于 f(n)的速度增長。 這種漸進估計對算法的理論分析和大致比較是非常有價值的,但在實踐中細節也可能造成差異。例如,一個低附加代價的O(n2)算法在n較小的情況下可能比一個高附加代價的 O(nlogn)算法運行得更快。當然,隨著n足夠大以后,具有較慢上升函數的算法必然工作得更快。 O(1) Temp=i;i=j;j=temp;???????????????????? 以上三條單個語句的頻度均為1,該程序段的執行時間是一個與問題規模n無關的常數。算法的時間復雜度為常數階,記作T(n)=O(1)。如果算法的執行時間不隨著問題規模n的增加而增長,即使算法中有上千條語句,其執行時間也不過是一個較大的常數。此類算法的時間復雜度是O(1)。 O(n^2) 2.1. 交換i和j的內容 ?????sum=0;?????????????????(一次) ?????for(i=1;i<=n;i++)???????(n次 ) ????????for(j=1;j<=n;j++) (n^2次 ) ?????????sum++;???????(n^2次 ) 解:T(n)=2n^2+n+1 =O(n^2) 2.2.??? ????for (i=1;i<n;i++) ????{ ????????y=y+1;?????????①??? ????????for (j=0;j<=(2*n);j++)???? ???????????x++;????????②?????? ????}????????? 解: 語句1的頻度是n-1 ??????????語句2的頻度是(n-1)*(2n+1)=2n^2-n-1 ??????????f(n)=2n^2-n-1+(n-1)=2n^2-2 ??????????該程序的時間復雜度T(n)=O(n^2).????????? O(n)?????? ?????????????????????????????????????????????????????? 2.3. ????a=0; ????b=1;??????????????????????① ????for (i=1;i<=n;i++) ② ????{?? ???????s=a+b; ③ ???????b=a; ④?? ???????a=s; ⑤ ????} 解:語句1的頻度:2,???????? ???????????語句2的頻度: n,???????? ??????????語句3的頻度: n-1,???????? ??????????語句4的頻度:n-1,???? ??????????語句5的頻度:n-1,?????????????????????????????????? ??????????T(n)=2+n+3(n-1)=4n-1=O(n). ????????????????????????????????????????????????????????????????????????????????????????????????? O(log2n ) 2.4. ?????i=1;???????① ????while (i<=n) ???????i=i*2; ② 解: 語句1的頻度是1,?? ??????????設語句2的頻度是f(n),???則:2^f(n)<=n;f(n)<=log2n???? ??????????取最大值f(n)= log2n, ??????????T(n)=O(log2n ) O(n^3) 2.5. ????for(i=0;i<n;i++) ????{?? ???????for(j=0;j<i;j++)?? ???????{ ??????????for(k=0;k<j;k++) ?????????????x=x+2;?? ???????} ????} 解:當i=m, j=k的時候,內層循環的次數為k當i=m時, j 可以取 0,1,...,m-1 , 所以這里最內循環共進行了0+1+...+m-1=(m-1)m/2次所以,i從0取到n, 則循環共進行了: 0+(1-1)*1/2+...+(n-1)n/2=n(n+1)(n-1)/6所以時間復雜度為O(n^3). ?????????????????????????????????? 我們還應該區分算法的最壞情況的行為和期望行為。如快速排序的最 壞情況運行時間是 O(n^2),但期望時間是 O(nlogn)。通過每次都仔細 地選擇基準值,我們有可能把平方情況 (即O(n^2)情況)的概率減小到幾乎等于 0。在實際中,精心實現的快速排序一般都能以 (O(nlogn)時間運行。 下面是一些常用的記法: 訪問數組中的元素是常數時間操作,或說O(1)操作。一個算法如 果能在每個步驟去掉一半數據元素,如二分檢索,通常它就取 O(logn)時間。用strcmp比較兩個具有n個字符的串需要O(n)時間。常規的矩陣乘算法是O(n^3),因為算出每個元素都需要將n對 元素相乘并加到一起,所有元素的個數是n^2。 指數時間算法通常來源于需要求出所有可能結果。例如,n個元 素的集合共有2n個子集,所以要求出所有子集的算法將是O(2n)的。指數算法一般說來是太復雜了,除非n的值非常小,因為,在 這個問題中增加一個元素就導致運行時間加倍。不幸的是,確實有許多問題 (如著名的“巡回售貨員問題” ),到目前為止找到的算法都是指數的。如果我們真的遇到這種情況,通常應該用尋找近似最佳結果的算法替代之。 |
轉載于:https://www.cnblogs.com/adc8868/p/8926183.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的第四百一十四节,python常用算法学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 管道符和作业控制 shell变量
- 下一篇: 在Linux系统安装Nodejs 最简单