python算法與數據結構-算法介紹(31)

1、算法和數據結構

什麼是算法和數據結構?若是將最終寫好運行的程序比做戰場,咱們程序員即是指揮做戰的將軍,而咱們所寫的代碼即是士兵和武器。程序員

那麼數據結構和算法是什麼?答曰:兵法!故,數據結構和算法是一名程序開發人員的必備基本功,不是一朝一夕就能練成絕世高手的。冰凍三尺非一日之寒,須要咱們平時不斷的主動去學習積累。算法

2、算法的引入

先來看一道題:若是 a+b+c=1000,且 a*a+b*b=c*c(a,b,c 爲天然數),如何求出全部a、b、c可能的組合?數組

普通解法:瀏覽器

import time

# 用於記錄計算開始的時間
start_time = time.time()
for a in range(0,1001):
    for b in range(0,1001):
        for c in range(0,1001):
            if a*a+b*b == c*c and a+b+c == 1000:
                print("a=%d,b=%d,c=%d"%(a,b,c))
# 用於記錄計算結束的時間
end_time = time.time()
print("本次運算用時總計%f秒"%(end_time-start_time))

運行結果爲:數據結構

a=0,b=500,c=500
a=200,b=375,c=425
a=375,b=200,c=425
a=500,b=0,c=500
本次運算用時總計397.615515秒

  請注意運行時間是397.615515秒那麼,若是本題稍微改一下,改成先來看一道題:若是 a+b+c=2000,且 a*a+b*b=c*c(a,b,c 爲天然數),如何求出全部a、b、c可能的組合?這個時候他們解題思路和a+b+c=1000是同樣的,無非就是將1000改成2000,而這種解決問題的思路就叫作算法,只不過算法也有好壞而已。數據結構和算法

3、算法的概念

  算法是計算機處理信息的本質,由於計算機程序本質上是一個算法來告訴計算機確切的步驟來執行一個指定的任務。通常地,當算法在處理信息時,會從輸入設備或數據的存儲地址讀取數據,把結果寫入輸出設備或某個存儲地址供之後再調用。算法是獨立存在的一種解決問題的方法和思想。對於算法而言,實現的語言並不重要,重要的是思想。算法能夠有不一樣的語言描述實現版本(如C描述、C++描述、Python描述等)函數

4、算法的五大特性

  1. 輸入: 算法具備0個或多個輸入
  2. 輸出: 算法至少有1個或多個輸出,算法必需要有輸出,否則算法有什麼意義,鬧着玩呢?因此必定要把算出了數據輸出使用。
  3. 有窮性: 算法在有限的步驟以後會自動結束而不會無限循環,而且每個步驟能夠在可接受的時間內完成
  4. 肯定性:算法中的每一步都有肯定的含義,不會出現二義性
  5. 可行性:算法的每一步都是可行的,也就是說每一步都可以執行有限的次數完成

5、案例算法優化

仍是針對上面的例子:若是 a+b+c=1000,且 a*a+b*b=c*c(a,b,c 爲天然數),如何求出全部a、b、c可能的組合?優化解法:性能

import time

# 用於記錄計算開始的時間
start_time = time.time()
# 注意這裏是兩重循環
for a in range(0,1001):
    for b in range(0,1001-a):
        c=1000-a-b
        if a*a+b*b == c*c:
            print("a=%d,b=%d,c=%d"%(a,b,c))
# 用於記錄計算結束的時間
end_time = time.time()
print("本次運算用時總計:%f秒"%(end_time-start_time))

運行結果爲:學習

a=0,b=500,c=500
a=200,b=375,c=425
a=375,b=200,c=425
a=500,b=0,c=500
本次運算用時總計316.337260秒

6、算法效率的衡量

  一、執行時間反應算法效率優化

  對於同一問題,咱們給出了兩種解決算法,在兩種算法的實現中,咱們對程序執行的時間進行了測算,發現兩段程序執行的時間相差懸殊(397.615515秒相比於316.337260秒),由此咱們能夠得出結論:實現算法程序的執行時間能夠反應出算法的效率,即算法的優劣。

  二、單靠時間絕對可信嗎?

  假設咱們將第二次嘗試的算法程序運行在一臺配置古老性能低下的計算機中,狀況會如何?極可能運行的時間並不會比在咱們的電腦中運行算法一的397.615515秒快多少。單純依靠運行的時間來比較算法的優劣並不必定是客觀準確的!程序的運行離不開計算機環境(包括硬件和操做系統),這些客觀緣由會影響程序運行的速度並反應在程序的執行時間上。那麼如何才能客觀的評判一個算法的優劣呢?

  三、時間複雜度與「大O記法」

  咱們假定計算機執行算法每個基本操做的時間是固定的一個時間單位,那麼有多少個基本操做就表明會花費多少時間單位。固然對於不一樣的機器環境而言,確切的單位時間是不一樣的,可是對於算法進行多少個基本操做(即花費多少時間單位)在規模數量級上倒是相同的,由此能夠忽略機器環境的影響而客觀的反應算法的時間效率。

  對於算法的時間效率,咱們能夠用「大O記法」來表示。

  「大O記法」:對於單調的整數函數f(),若是存在一個整數函數g()和實常數c>0,使得對於充分大的n總有f(n)<=c*g(n),就說函數g是f的一個漸近函數(忽略常數),記爲f(n)=O(g(n))。也就是說,在趨向無窮的極限意義下,函數f的增加速度受到函數g的約束,亦即函數f與函數g的特徵類似。

時間複雜度:假設存在函數g(),使得算法A處理規模爲n的問題示例所用時間爲T(n)=O(g(n)),則稱O(g(n))爲算法A的漸近時間複雜度,簡稱時間複雜度,記爲T(n)

  • 算法完成工做最少須要多少基本操做,即最優時間複雜度
  • 算法完成工做最多須要多少基本操做,即最壞時間複雜度
  • 算法完成工做平均須要多少基本操做,即平均時間複雜度

  四、時間複雜度的基本計算規則

  1. 基本操做,即只有常數項,認爲其時間複雜度爲O(1)
  2. 順序結構,時間複雜度按加法進行計算
  3. 循環結構,時間複雜度按乘法進行計算
  4. 分支結構,時間複雜度取最大值
  5. 判斷一個算法的效率時,每每只須要關注操做數量的最高次項,其它次要項和常數項能夠忽略
  6. 在沒有特殊說明時,咱們所分析的算法的時間複雜度都是指最壞時間複雜度

7、案例的算法分析

for a in range(0,1001):
    for b in range(0,1001):
        for c in range(0,1001):
            if a*a+b*b == c*c and a+b+c == 1000:
                print("a=%d,b=%d,c=%d"%(a,b,c))

時間複雜度:T(n) = O(n*n*n) = O(n^3)

優化後:

for a in range(0,1001):
    for b in range(0,1001-a):
        c=1000-a-b
        if a*a+b*b == c*c:
            print("a=%d,b=%d,c=%d"%(a,b,c))

時間複雜度:T(n) = O(n*n) = O(n^2), 因而可知,咱們嘗試的第二種算法要比第一種算法的時間複雜度好多的。

8、常見的時間複雜度  

注意:常常將log2n(以2爲底的對數)簡寫成logn

 

所消耗的時間從小到大:O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(n^n)

9、拿時間換空間,用空間換時間

算法的時間複雜度和空間複雜度是能夠相互轉化的。
谷歌瀏覽器相比於其餘的瀏覽器,運行速度要快。是由於它佔用了更多的內存空間,以空間換取了時間。
算法中,例如判斷某個年份是否爲閏年時,若是想以時間換取空間,算法思路就是:當給定一個年份時,判斷該年份是否能被4或者400整除,若是能夠,就是閏年。
若是想以空間換時間的話,判斷閏年的思路就是:把全部的年份先判斷出來,存儲在數組中(年份和數組下標對應),若是是閏年,數組值是1,不然是0;當須要判斷某年是否爲閏年時,直接看對應的數組值是1仍是0,不用計算就能夠立刻知道。
 

10、算法VS程序

  不少人誤覺得程序就是算法,其實否則:算法是解決某個問題的想法、思路;而程序是在心中有算法的前提下編寫出來的能夠運行的代碼。例如,要解決依次輸出一維數組中的數據元素的值的問題,首先想到的是使用循環結構( for 或者 while ),在有這個算法的基礎上,開始編寫程序。因此,算法至關因而程序的雛形。當解決問題時,首先心中要有解決問題的算法,圍繞算法編寫出程序代碼。

相關文章
相關標籤/搜索