准備考研的過程中,復習數據結構和算法時先看的是嚴蔚敏老師的《數據結構》,這本書雖然好但是對時間復雜度和算法的漸進性講解太少,讀完之后對其依然沒有深刻的理解,於是開始啃《算法導論》,不得不說這本書很難啃,但是確實啃清楚了算法的時間復雜度和漸進性。這篇博客我會用到初中程度的代數知識來幫助大家徹底理解。
我選擇插入排序作為例子因為這個算法的思路足夠簡單,可以很容易的分析出最好情況和最壞情況。我們先來看一下插入排序的偽代碼,我使用C++來書寫代碼,有注釋:
//插入排序的算法思路很簡單,聯想打撲克牌時理順手中牌的時候,你從左往右依次檢查你的牌,並將其和前面的牌進行比較,然后將其插入正確的位置 void insertion_sort(int arr[],int length){ int key;//key作為當前你所檢查的這張牌,為了方便表達我們稱之為 關鍵牌 for(int i=1;i<length;i++){//從第二張牌開始,一直迭代到最后一張牌 key = arr[i];//將本次需要排序的牌拿出,作為關鍵牌 int j = i-1;//從關鍵牌的前一張開始往前檢查,對比大小 //當被對比的牌比關鍵牌大時,關鍵牌前面所有的牌都比關鍵牌大時,把牌往后挪動一個位置 while(j>-1 && arr[j] > key){ arr[j+1] = arr[j]; j--; } arr[j+1] = key;//將關鍵插入正確的位置 } }
那么我們該如何知道,這段代碼在實際執行時所花費的時間呢?當然可以上機測試,但是那樣是經驗論者和低端玩家干的事情,這里我們需要一些簡單的數學知識和邏輯分析就能算出運行時間,我們假設,這次共排序一個長度為n的數組,那么每句代碼執行所需要的時間代價和執行次數可以用下表表示:
代碼 時間代價 執行次數
int key c1 1次
int i=1;i<length;i++ c2 n次
key = arr[i] c3 n-1次
int j = i-1 c4 n-1次
while(j>-1 && arr[j] > key) c5 這里我們無法判斷具體的執行次數,但是知道外層循環要執行n-1次,假設第i次循環中這里執行k(i)次,那么共執行k(1)+k(2)+...+k(n-1)次
arr[j+1] = arr[j] c6 循環內的語句總比循環數少1,於是共執行(k(1)-1)+(k(2)-1)+...+(k(n-1)-1)次
j--; c7 同理,共執行(k(1)-1)+(k(2)-1)+...+(k(n-1)-1)次
arr[j+1] = key c8 n-1次