以前学过的都忘了,也没好好作过总结,如今总结一下。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)