数据算法与结构基本知识
數(shù)據(jù)結(jié)構(gòu)與算法作用
計算機界著名公式,由瑞士計算機科學(xué)家尼克勞斯·威茨(Niklaus Wirth)提出,也因此獲得圖靈獎。
程序 = 數(shù)據(jù)結(jié)構(gòu) + 算法
算法的提出
算法的概念
算法是計算機處理信息的本質(zhì),因為計算機程序本質(zhì)上是一個算法來告訴計算機確切的步驟來執(zhí)行一個指定的任務(wù)。一般地,當(dāng)算法在處理信息時,會從輸入設(shè)備或數(shù)據(jù)的存儲地址讀取數(shù)據(jù),把結(jié)果寫入輸出設(shè)備或某個存儲地址供以后再調(diào)用。
算法是獨立存在的一種解決問題的方法和思想。
對于算法而言,實現(xiàn)的語言并不重要,重要的是思想。
算法可以有不同的語言描述實現(xiàn)版本(如C描述、C++描述、Python描述等),我們現(xiàn)在是在用Python語言進行描述實現(xiàn)。
算法的五大特性
算法效率衡量
執(zhí)行時間反應(yīng)算法效率
對于同一問題,我們給出了兩種解決算法,在兩種算法的實現(xiàn)中,我們對程序執(zhí)行的時間進行了測算,發(fā)現(xiàn)兩段程序執(zhí)行的時間相差懸殊(214.583347秒相比于0.182897秒),由此我們可以得出結(jié)論:實現(xiàn)算法程序的執(zhí)行時間可以反應(yīng)出算法的效率,即算法的優(yōu)劣。
單靠時間值絕對可信嗎?
假設(shè)我們將第二次嘗試的算法程序運行在一臺配置古老性能低下的計算機中,情況會如何?很可能運行的時間并不會比在我們的電腦中運行算法一的214.583347秒快多少。
單純依靠運行的時間來比較算法的優(yōu)劣并不一定是客觀準(zhǔn)確的!
程序的運行離不開計算機環(huán)境(包括硬件和操作系統(tǒng)),這些客觀原因會影響程序運行的速度并反應(yīng)在程序的執(zhí)行時間上。那么如何才能客觀的評判一個算法的優(yōu)劣呢?
時間頻度
一個算法執(zhí)行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。并且一個算法花費的時間與算法中語句的執(zhí)行次數(shù)成正比例,哪個算法中語句執(zhí)行次數(shù)多,它花費時間就多。一個算法中的語句執(zhí)行次數(shù)稱為語句頻度或時間頻度。記為T(n)。
時間復(fù)雜度與“大O記法”
上面提到的時間頻度T(n)中,n稱為問題的規(guī)模,當(dāng)n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現(xiàn)什么規(guī)律,為此我們引入時間復(fù)雜度的概念。一般情況下,算法中基本操作重復(fù)執(zhí)行的次數(shù)是問題規(guī)模n的某個函數(shù),用T(n)表示,如果存在一個整數(shù)函數(shù)g和實常數(shù)c>0,使得對于充分大的n總有T(n)<=c*g(n),就說函數(shù)g是T(n)函數(shù)的一個漸近函數(shù)(忽略常數(shù)),記為T(n)=O(g(n)),它稱為算法的漸進時間復(fù)雜度,簡稱時間復(fù)雜度。這種用O( )來體現(xiàn)算法時間復(fù)雜度的記法,我們稱之為大O表示法。
大O表示法實際就是去掉T(n)函數(shù)的最高階項系數(shù)、低階項和常數(shù)項,只保留最高階項。如T(n)函數(shù)為5n3 + 3n + 5,使用大O表示法則時間復(fù)雜度為O(n3)。
如何理解“大O記法”
對于算法的效率衡量,最重要的是其數(shù)量級和趨勢,這些是分析算法效率的主要部分。而計量算法基本操作數(shù)量的規(guī)模函數(shù)中那些常量因子可以忽略不計。例如,可以認為3n2和100n2屬于同一個量級,如果兩個算法處理同樣規(guī)模實例的代價分別為這兩個函數(shù),就認為它們的效率“差不多”,都為n2級。
最壞時間復(fù)雜度
分析算法時,存在幾種可能的考慮:
- 算法完成工作最少需要多少基本操作,即最優(yōu)時間復(fù)雜度
- 算法完成工作最多需要多少基本操作,即最壞時間復(fù)雜度
- 算法完成工作平均需要多少基本操作,即平均時間復(fù)雜度
對于最優(yōu)時間復(fù)雜度,其價值不大,因為它沒有提供什么有用信息,其反映的只是最樂觀最理想的情況,沒有參考價值。
對于最壞時間復(fù)雜度,提供了一種保證,表明算法在此種程度的基本操作中一定能完成工作。
對于平均時間復(fù)雜度,是對算法的一個全面評價,因此它完整全面的反映了這個算法的性質(zhì)。但另一方面,這種衡量并沒有保證,不是每個計算都能在這個基本操作內(nèi)完成。而且,對于平均情況的計算,也會因為應(yīng)用算法的實例分布可能并不均勻而難以計算。
因此,我們主要關(guān)注算法的最壞情況,亦即最壞時間復(fù)雜度。
時間復(fù)雜度的幾條基本計算規(guī)則
常見時間復(fù)雜度
| 12 | O(1) | 常數(shù)階 |
| 2n+3 | O(n) | 線性階 |
| 3n2+2n+1 | O(n2) | 平方階 |
| 5log2n+20 | O(logn) | 對數(shù)階 |
| 2n+3nlog2n+19 | O(nlogn) | nlogn階 |
| 6n3+2n2+3n+4 | O(n3) | 立方階 |
| 2n | O(2n) | 指數(shù)階 |
注意,經(jīng)常將log2n(以2為底的對數(shù))簡寫成logn
常見時間復(fù)雜度之間的關(guān)系
所消耗的時間從小到大
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
Python內(nèi)置類型性能分析
timeit模塊
timeit模塊可以用來測試一小段Python代碼的執(zhí)行速度。
class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)
Timer是測量小段代碼執(zhí)行速度的類。
stmt參數(shù)是要測試的代碼語句(statment);
setup參數(shù)是運行代碼時需要的設(shè)置;
timer參數(shù)是一個定時器函數(shù),與平臺有關(guān)。
timeit.Timer.timeit(number=1000000)
Timer類中測試語句執(zhí)行速度的對象方法。number參數(shù)是測試代碼時的測試次數(shù),默認為1000000次。方法返回執(zhí)行代碼的耗時,一個float類型的秒數(shù)。
list內(nèi)置操作的時間復(fù)雜度
dict內(nèi)置操作的時間復(fù)雜度
數(shù)據(jù)結(jié)構(gòu)
我們?nèi)绾斡肞ython中的類型來保存一個班的學(xué)生信息? 如果想要快速的通過學(xué)生姓名獲取其信息呢?
實際上當(dāng)我們在思考這個問題的時候,我們已經(jīng)用到了數(shù)據(jù)結(jié)構(gòu)。列表和字典都可以存儲一個班的學(xué)生信息,但是想要在列表中獲取一名同學(xué)的信息時,就要遍歷這個列表,其時間復(fù)雜度為O(n),而使用字典存儲時,可將學(xué)生姓名作為字典的鍵,學(xué)生信息作為值,進而查詢時不需要遍歷便可快速獲取到學(xué)生信息,其時間復(fù)雜度為O(1)。
我們?yōu)榱私鉀Q問題,需要將數(shù)據(jù)保存下來,然后根據(jù)數(shù)據(jù)的存儲方式來設(shè)計算法實現(xiàn)進行處理,那么數(shù)據(jù)的存儲方式不同就會導(dǎo)致需要不同的算法進行處理。我們希望算法解決問題的效率越快越好,于是我們就需要考慮數(shù)據(jù)究竟如何保存的問題,這就是數(shù)據(jù)結(jié)構(gòu)。
在上面的問題中我們可以選擇Python中的列表或字典來存儲學(xué)生信息。列表和字典就是Python內(nèi)建幫我們封裝好的兩種數(shù)據(jù)結(jié)構(gòu)。
概念
數(shù)據(jù)結(jié)構(gòu)是計算機存儲、組織數(shù)據(jù)的方式。數(shù)據(jù)結(jié)構(gòu)是指相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。
為了解決問題,需要將數(shù)據(jù)保存下來,然后根據(jù)數(shù)據(jù)的存儲方式來設(shè)計算法實現(xiàn)進行處理,那么數(shù)據(jù)的存儲方式不同就會導(dǎo)致需要不同的算法進行處理。我們希望算法解決問題的效率越快越好,于是我們就需要考慮數(shù)據(jù)究竟如何保存的問題,這就是數(shù)據(jù)結(jié)構(gòu)。
總結(jié)
以上是生活随笔為你收集整理的数据算法与结构基本知识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python变量以及类型(含笔记)
- 下一篇: raptor累乘流程图_Markdown