一、程序的定義
程序 = 數據結構 + 算法
程序是為了解決實際問題而存在的。然而為了解決問題,必定會使用到某些數據結構以及設計一個解決這種數據結構的算法。例如:有些交友網站能夠列出你可能認識的好友,是為了解決網絡聊天的問題。要解決這個問題,必定會使用到圖這種數據結構(最短路徑), 然而光有數據結構還不行,要實現這個功能,必須在圖這種數據結構的基礎上,設計一種算法,一步一步的操作,這些一步一步的操作就是算法,算法是特定問題求解步驟的描述。 再如: abbyy軟件(一款OCR識別軟件,簡單說就是把圖片還原成word的形式), 是為了解決圖片處理的問題。要解決表格還原這個問題,必定會使用到"樹"這種數據結構,在樹這種結構上,一步一步實現還原功能。類似的軟件還有五子棋中的判斷輸贏算法, 走迷宮算法等等。
二、數據結構的定義
一般來說,用計算機解決一個具體問題時,首先從具體問題抽象出一個適當的數學模型(也就是數據結構), 然后設計一個解決此數學模型的算法。
數據結構: 我們要研究對象的數據元素之間的關系。通常我們說的數據結構是一種邏輯結構,程序運行時必須把這些邏輯結構轉為物理結構。
常見邏輯數據結構:集合結構(兩個函數中分別定義的局部變量,兩者沒有任何關系),線性結構,樹形結構,圖形結構。
物理結構:順序存儲,鏈式存儲。
三、算法的定義
算法是特定問題求解步驟的描述
算法是獨立存在的一種解決問題的方法和思想
四、成為一個算法需要滿足的條件
要看是否是一個算法,必須滿足下面的這些條件
1. 輸入
算法具有0個或者多個輸入
2. 輸出
至少有1個或者多個輸出
3. 有窮性
算法在執行有限的步驟之后會自動結束而不會進行死循環狀態
4. 確定性
算法中的每一步都有意義,不會出現二義性
5. 可行行
算法中每一步都必須可行
五、如何評判一個算法的好壞
1、正確性:
對於合法輸入能夠得到滿足的結果
算法能夠處理非法處理,並得到合理結果
算法對於邊界數據和壓力數據都能得到滿足的結果
2、可讀性:
算法要方便閱讀,理解和交流,只有自己能看得懂,其它人都看不懂,談和好算法。
3、健壯性:
算法不應該產生莫名其妙的結果,一會兒正確,一會兒又是其它結果
4、高性價比
利用最少的時間和資源得到滿足要求的結果,可以通過(時間復雜度和空間復雜度來判定)
六、時間復雜度與空間復雜度
通常判定一種算法的效率可以采用事后統計法和事前分析估算
事后統計法缺點:
必須編寫相應的測試程序,嚴重依賴硬件和運行時的環境,算法的數據采集相當的困難。
事前分析估算:
主要取決於問題的規模。
1、時間復雜度
公式: T(n) = O( f(n) ); 其中f(n)是問題規模n的函數,也就是執行某個操作的次數。
在沒有特殊說明的情況下,我們所分析的時間復雜度都是指最壞的時間復雜度
常見時間復雜度:
此外還有O(n!)等
各個時間復雜度的關系:
2、空間復雜度
公式: S(n) = O( f(n) ) 其中f(n)是在問題規模為n時所占用的內存空間大小;
大O表示法同樣也適合空間復雜度,這里就不在重復說明了。
3.時間復雜度與空間復雜度的策略
多算情況下,算法的執行時所用的時間更令人關注;
如果有必要,可以增加空間復雜度來降低時間復雜度;
同理,也可以添加時間復雜度來降低空間復雜度,例如像51單片機,嵌入式設備,內存資源是很珍貴的,就可以通過增加時間復雜度來降低空間復雜度;
因此,我們在實現算法的時候,需要分析具體問題對執行時間和空間的要求;
下面看一個通過添加空間復雜度來降低時間復雜度的例子:
#include <stdio.h> #include <stdlib.h> //功能: 從1---1000中,找出出現次數最多的那個數字 int Search(int array[], int nLen); int main() { int array[] = {1, 1, 3, 4, 5, 6, 6, 6, 2, 3}; Search( array, sizeof(array) / sizeof(array[0]) ); return 0; } int Search(int array[], int nLen) { int anTemp[1000] = {0}; int nIndex = 0; int nTempPos = 0; int nMax = 0; //把1---1000中的某一個數存儲在anTemp數組中的位置 //把把1---1000中的某一個數的個數加1 for(nIndex = 0; nIndex <nLen; nIndex++) { nTempPos = array[nIndex] - 1; anTemp[nTempPos]++; } //在anTemp中找出最大值 for(nIndex = 0; nIndex < 1000; nIndex++) { if(nMax < anTemp[nIndex]) { nMax = anTemp[nIndex]; } } //輸出1---1000之間出現最多的那個數字 for(nIndex = 0; nIndex < 1000; nIndex++) { if(nMax == anTemp[nIndex]) { printf("%d\n", nIndex + 1); } } return 0; }
在這個例子中,通過開辟一個int anTemp[1000]大小的存儲空間,用來存放1---1000中每個數字出現的次數,雖然增加了空間復雜度,但是降低了時間復雜度。
類似的例子還有表驅動算法,也是通過開辟一個空間,然后從該空間中找到需要的內容。舉個例子:像計算某年是否是閏年,就可以通過開辟一個2050大小的空間(1--2050年),並根據事先已經知道的結果,是閏年的就設為1,否則設為0;例如判斷2014是否是閏年,就只需要查找這個數組中索引為2013那個元素內容是否為1就可以了。