以前學過的都忘了,也沒好好作過總結,如今總結一下。python
時間複雜度和空間複雜度的概念:算法
一、空間複雜度:
是程序運行因此須要的額外消耗存儲空間,通常的遞歸算法就要有o(n)的空間複雜度了,簡單說就是遞歸集算時一般是反覆調用同一個方法,遞歸n次,就須要n個空間。
二、時間複雜度:
一個算法花費的時間與算法中語句的執行次數成正比例,哪一個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲T(n)。
通常狀況下,算法中基本操做重複執行的次數是問題規模n的某個函數,用T(n)表示,如有某個輔助函數f(n),使得當n趨近於無窮大時,T(n)/f (n)的極限值爲不等於零的常數,則稱f(n)是T(n)的同數量級函數。記做T(n)=O(f(n)),稱O(f(n)) 爲算法的漸進時間複雜度,簡稱時間複雜度。
在各類不一樣算法中,若算法中語句執行次數爲一個常數,則時間複雜度爲O(1),另外,在時間頻度不相同時,時間複雜度有可能相同,如T(n)=n2+3n+4與T(n)=4n2+2n+1它們的頻度不一樣,但時間複雜度相同,都爲O(n2)。
按數量級遞增排列,常見的時間複雜度有:
常數階O(1),對數階O(log2n),線性階O(n),
線性對數階O(nlog2n),平方階O(n2),立方階O(n3),...,
目前我已經學過的排序算法包括數組
一、二次排序:app
一、插入排序dom
二、選擇排序函數
二、遞歸排序:spa
一、歸併排序code
二、快速排序htm
三、希爾排序blog
四、冒泡排序
1、冒泡排序
原理: 冒泡排序就是把小的元素往前調或者把大的元素日後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。
評價:是效率最低的一種排序算法。
時間複雜度:最差和平均均爲O(n2)
穩定性:因爲相等的元素不須要交換,因此比較穩定
代碼:
C實現:
#include<stdio.h> #include<stdlib.h> #include<time.h> int msort(int array[],int n) { int exchange = 0; int i,j; i=j=0; for(i=0;i<n;i++) { j=n-1; while(j > i) { int temp=0; //printf("%d",array[j]); if (array[j]<array[j-1]) { temp = array[j]; printf("%d",temp); array[j] = array[j-1]; array[j-1] = temp; exchange = 1; } j=j-1; } if (exchange == 0) break; } for(i=0;i<n;i++) printf("%d\n",array[i]); } int main(void) { int SIZE=9; int array[9]={5,2,8,2,7,9,10,20,15}; int i=0; for(i=0;i<SIZE;i++) printf("%d\n",array[i]); msort(array,SIZE); return 0; }
Python實現:
import timeit def msort(array): exchange=False for i in xrange(len(array)): j=len(array)-1 while(j>i): if array[j]<array[j-1]: array[j-1],arra[j]=array[j],array[j-1] exchange=True j=j-1 if exchange!=True: break print array def main(): array=list(range(0,10000)) msort(array) if __name__=="__main__": t=timeit.Timer("main()",'from __main__ import main') print t.timeit(1)
2、選擇排序
原理:簡單點說就是從數組第一個位置開始,給每一個位置在剩餘的元素中都找到最小的值放上去。
評價:因爲每次都要尋找最值,因此選擇排序效率不高
時間複雜度:最壞,最優和平均時間複雜度都是O(n2).
穩定性:因爲交換,可能致使相等元素的先後順序發生變化,因此不穩定。好比 舉個例子,序列5 8 5 2 9, 咱們知道第一遍選擇第1個元素5會和2交換,那麼原序列中2個5的相對先後順序就被破壞了
代碼:
C實現:
#include<stdio.h> #include<stdlib.h> void ssort(int array[],int n) { int i,j; int small; for(i=0;i<n;i++) { small=i; for(j=i+1;j<n;j++) { if (array[j]<array[small]) small=j; } int temp=0; if (small!=i) { temp=array[i]; array[i]=array[small]; array[small]=temp; } } for(i=0;i<n;i++) printf("%d ",array[i]); } int main(void) { int array[7]={7,3,1,6,4,2,8}; ssort(array,7); }
Python實現:
def ssort(array): for i in xrange(0,len(array)): j=i+1 small=i while j<len(array): if array[j]<array[small]: small=j; j+=1 if i!=small: array[small],array[i] = array[i],array[small] return array array=[2,62,7,3,8,1,1] print 'any',all(array) print ssort(array)
3、插入排序:
原理:爲當前有序序列插入元素,插入到正確的位置。 固然,剛開始這個有序的小序列只有1個元素,就是第一個元素。比較是從有序序列的末尾開 始,也就是想要插入的元素和已經有序的最大者開始比起,若是比它大則直接插入在其後面,不然一直往前找直到找到它該插入的位置。
評價:對於比較有序的數組列表來講,效率是線性的,至關快。
穩定度:若是遇見一個和插入元素相 等的,那麼插入元素把想插入的元素放在相等元素的後面。因此,相等元素的先後順序沒有改變,從原無序序列出去的順序就是排好序後的順序,因此插入排序是穩 定的。
時間複雜度:最差的狀況是逆序的,須要O(n2),平均也是O(n2),最優的是線性的。
C實現
#include<stdio.h> #include<stdlib.h> int isort(int array[],int n) { int i=0; int j; for(i=1;i<n;i++) { int temp=array[i]; for(j=i;j>0&&array[j-1]>temp;j--) { array[j]=array[j-1]; } array[j]=temp; } for(i=0;i<7;i++) { printf("%d ",array[i]); } } int main(void) { int array[7]={8,2,7,1,9,3,0}; int result[7]; isort(array,7); }
Python實現:
def isort(array): for i in xrange(1,len(array)): temp=array[i] j=i while j>0 and array[j-1]>temp: array[j]=array[j-1] j=j-1 array[j]=temp return array print isort([6,3,2,1,8,4])
4、歸併排序
原理:採用分治法,將數組分紅兩部分元素,如此下去,知道只剩下一個元素,採用遞歸調用。兩部分數組比較,須要一個臨時數組,存儲有序值。
評價:算法很快,可是須要分配臨時數組,耗費內存。
穩定度:因爲在比較時,兩個相等值能夠保證位置不變,因此是穩定的。
時間複雜度:最優,最差和平均都是O(nlogn)
代碼:
Python:
def merge(L1,L2): sorted_array=[] while L1 and L2: if L1[0] <= L2[0]: sorted_array.append(L1.pop(0)) else: sorted_array.append(L2.pop(0)) if L1: sorted_array.extend(L1) if L2: sorted_array.extend(L2) return sorted_array def mersort(array): if len(array)<=1: return array center=int(len(array)/2) return merge(mersort(array[:center]),mersort(array[center:])) if __name__=="__main__": array=[8,20,15,4,6,3,7,2,1,9] print mersort(array)
5、快速排序
原理:和歸併排序的思想是相同的,都採用分治法,可是不一樣的是須要選擇一個基準數,根據基準數把數組分爲兩段,比基準數小的在左邊,比基準數大的在右邊。左右兩邊再分別採用這種方法,如此遞歸調用下去,知道只剩下一個元素。
評價:關鍵是找到基準數,基準數通常是隨機選擇三個值,選擇中間值,或者選擇數組第一個元素,可是若是第一個元素是最小的或最大的就糟糕了。
穩定性:不穩定。 好比序列爲 5 3 3 4 3 8 9 10 11, 如今基準元素5和3(第5個元素,下標從1開始計)交換就會把元素3的穩定性打亂,因此快速排序是一個不穩定的排序算法
時間複雜度:最壞的狀況是O(n2),最好喝平均都是O(nlogn)
python實現:
import random def partition(array,left,right): if right-left==1: if array[left]>array[right]: array[left],array[right]=array[right],array[left] return None base=array[left] big_index,small_index = left+1,right while big_index < small_index: while array[big_index] <= base and big_index < right: big_index += 1 while array[small_index] >= base and small_index > left: small_index -=1 if big_index < small_index: array[big_index],array[small_index] = array[small_index],array[big_index] array[left],array[small_index] = array[small_index],base return small_index def qsort(array,left,right): if right > left: mid=partition(array,left,right) if mid is not None: qsort(array,left,mid) qsort(array,mid+1,right) if __name__=="__main__": array=[] for i in xrange(0,50): array.append(random.randint(0,30)) qsort(array,0,(len(array)-1)) print array
其實快速排對大數組頗有效率,但若是小數組,插入排序比較好,經驗代表,元素數目小於15時,能夠改成插入排序
Python:
import random from insert.isort import import isort def partition(array,left,right): if right-left==1: if array[left]>array[right]: array[left],array[right]=array[right],array[left] return None base=array[left] big_index,small_index = left+1,right while big_index < small_index: while array[big_index] <= base and big_index < right: big_index += 1 while array[small_index] >= base and small_index > left: small_index -=1 if big_index < small_index: array[big_index],array[small_index] = array[small_index],array[big_index] array[left],array[small_index] = array[small_index],base return small_index def qsort(array,left,right): if right-left>15: mid=partition(array,left,right) if mid is not None: qsort(array,left,mid) qsort(array,mid+1,right) else: isort(array) if __name__=="__main__": array=[] for i in xrange(0,50): array.append(random.randint(0,30)) qsort(array,0,(len(array)-1)) print array
6、希爾排序
原理:採用不一樣的步長,分別進行插入排序,直到步長爲1.原理解釋最直觀的以下:
例如,假設有這樣一組數[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],若是咱們以步長爲5開始進行排序,咱們能夠經過將這列表放在有5列的表中來更好地描述算法,這樣他們就應該看起來是這樣:
13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
而後咱們對每列進行排序:
10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
將上述四行數字,依序接在一塊兒時咱們獲得:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].這時10已經移至正確位置了,而後再以3爲步長進行排序:
10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
排序以後變爲:
10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
最後以1步長進行排序(此時就是簡單的插入排序了)。
評價:選擇步長是關鍵,選擇好了,比較快,通常步長初始選擇數組長度除以2,一直除以2,一直到步長爲1.
穩定度:不穩定,不一樣部分數組排序,頗有可能打破相等元素的順序。
時間複雜度:(摘抄):
須要大量的輔助空間,和歸併排序同樣容易實現。希爾排序是基於插入排序的一種算法, 在此算法基礎之上增長了一個新的特性,提升了效率。希爾排序的時間複雜度與增量序列的選取有關,例如希爾增量時間複雜度爲O(n²),而Hibbard增量的希爾排序的時間複雜度爲O(
),可是現今仍然沒有人能找出希爾排序的精確下界。希爾排序沒有快速排序算法快 O(n(logn)),所以中等大小規模表現良好,對規模很是大的數據排序不是最優選擇。可是比O(
)複雜度的算法快得多。而且希爾排序很是容易實現,算法代碼短而簡單。 此外,希爾算法在最壞的狀況下和平均狀況下執行效率相差不是不少,與此同時快速排序在最壞的狀況下執行的效率會很是差。專家們提倡,幾乎任何排序工做在開始時均可以用希爾排序,若在實際使用中證實它不夠快,再改爲快速排序這樣更高級的排序算法. 本質上講,希爾排序算法是直接插入排序算法的一種改進,減小了其複製的次數,速度要快不少。 緣由是,當n值很大時數據項每一趟排序須要的個數不多,但數據項的距離很長。當n值減少時每一趟須要和動的數據增多,此時已經接近於它們排序後的最終位置。 正是這兩種狀況的結合才使希爾排序效率比插入排序高不少。
Python實現:
def shsort(array): interval = len(array)/2 while interval >= 1: i = interval while i < len(array): if array[i] < array[i-interval]: j=i-interval temp=array[i] while j >=0 and array[j] >temp: array[j+interval]=array[j] j-=interval array[j+interval]=temp i+=1 interval/=2 return array if __name__=="__main__": array=[3,6,9,5,7,4,8,2,1] print shsort(array)
7、基數排序
原理:又名桶子排序,有10個桶。首先把個位數按照順序放到桶子中,個位數相同的就放在同一個桶子裏;而後再按照十位數的大小順序放到桶子裏,依次類推,最後獲得結果。
評價:基數排序的時間複雜度是 O(k·n),其中n是排序元素個數,k是數字位數。注意這不是說這個時間複雜度必定優於O(n·log(n)),k的大小取決於數字位的選擇(好比比特位數),和待排序數據所屬數據類型的全集的大小;k決定了進行多少輪處理,而n是每輪處理的操做數目。
以排序n個不一樣整數來舉例,假定這些整數以B爲底,這樣每位數都有B個不一樣的數字,k = logB(N),N是待排序數據類型全集的勢。雖然有B個不一樣的數字,須要B個不一樣的桶,但在每一輪處理中,判斷每一個待排序數據項只須要一次計算肯定對應數位的值,所以在每一輪處理的時候都須要平均n 次操做來把整數放到合適的桶中去,因此就有:
因此,基數排序的平均時間T就是:
其中前一項是一個與輸入數據無關的常數,固然該項不必定小於logn
穩定度:很穩定. 基數排序基於分別排序,分別收集,因此其是穩定的排序算法
時間複雜度:O(k·n)
Python實現:
def rsort(array): length = len(str(max(array))) locat = 0 while locat < length: bucket = [] for n in xrange(0,10): bucket.append([]) for i in array: index=i%10 if not locat else i/(locat*10)%10 bucket[index].append(i) array = [] for i in bucket: array.extend(i) locat += 1 return array print rsort([35,8611,84,36,745,154,39,4,3])
8、堆排序
原理:構成堆,將末端值與根節點交換
穩定度:不穩定
時間複雜度:nlogn
Python實現:
def make_heap(array,start,end): lchild = lambda x:2*x+1 rchild = lambda x:2*x+2 root = start while True: left = lchild(root) if left > end: break right = rchild(root) child = right if right <= end and array[left]<array[right] else left if array[child] <= array[root]: break else: array[root],array[child] = array[child],array[root] root = child def list_heap(array): for i in xrange(len(array)/2,-1,-1): make_heap(array,i,len(array)-1) def hsort(array): list_heap(array) for end in xrange(len(array)-1,0,-1): array[0],array[end] = array[end],array[0] make_heap(array,0,end-1) return array
if __name__=="__main__": array=[3,7,1,8,230,56,100,34,12,40,9,54,67,24,26] print hsort(array)