算法(Algorithm)
一个有限指令集
接受一些输入(有些情况下不需要输入)
产生输出
一定在有限步骤之后终止
每一条指令必须
有充分明确的目标,不可以有歧义
计算机能处理的范围之内
描述应不依赖于任何一种计算机语言以及具体的实现手段
例子:
void SelectionSort(int List[],int N) {/*将N个整数List[0]...List[N-1]进行非递减排序*/ for( i = 0;i < N; i++){ Minposition = ScanForMin(list,i,N-1) 从Lsit[i]到List[N-1]中找最小元,并将其位置赋给MinPosition; Swap(List[i],List[MinPostion]); 将未排序部分的最小元换到有序部分的最后位置; } }
抽象-
List到底是数组还是链表(虽然看上去很像数组)?
Swap用函数还是用宏去实现?
什么是好的算法
空间复杂度S(n)--根据算法写成的程序在执行时占用存储单元的长度。这个长度往往与输入数据的规模有关。空间复杂度过高的算法可能导致使用的内存超限,造成程序非正常中断。
时间复杂度T(n)--根据算法写成的程序在执行时耗费时间的长度。这个长度往往也与输入数据的规模有关。事件复杂度过高的低效算法可能导致我们在有生之年都等不到运行结果。
例子:
void PrintN(int N) { if(N){ PrintN(N - 1); printf(“%d\n”,N); } return; }
机器运算加减法要比运算乘除法快很多。
double f (int n,double a[], double x) { int i; double p = a[n]; for( i = n; i > 0; i--) p =a[i - 1] + x * p; return p; }
使用了N次乘法 T(n) = C * n
double f (int n,double a[], double x) { int i; double p = a[0]; for( i = 1; i <= n; i++) p+=(a[i] * pow(x,i)); return p; }
使用了(1+2+..+n) = (n2 + n) / 2次乘法 T(n) = C1n2 + C2n
在分析一般算法的效率时,我们经常关注下面两种复杂度
最坏情况复杂度Tworst(n)
平均复杂度Tavg(n)
Tavg(n) <= Tworst(n)
复杂度的渐进表示法
T(n) = O(f(n))表示存在常数C > 0,n0>0使得当n >=n0 时有T(n) <=C*F(n)
T(n) = Ω(g(n))表示存在常数C >0, n0>0使得当n>=n0 时有T(n) >= C*g(n)
T(n) = θ(h(n))表示同时有T(n) =O(h(n))和T(n) = Ω(h(n))
复杂度分析小窍门
若两端算法分别有复杂度T1(n) = O(f1(n))和T2(n) = O(f2(n)),则
T1(n) + T2(n) = max(O(f1(n)),O(f2(n)))
T1(n) + T2(n) = O(f1(n) *f2(n))
若T(n)是关于n的k阶多项式,那么T(n) = θ(nk)
一个for循环的时间复杂度等于循环次数乘以循环体代码的复杂度
if-else结构的复杂度取决于if的条件判断复杂度和两个分支部分的复杂度,总体复杂度取三者中最大
例子:给定N个整数的序列{A1,A2,...,AN},求函数f(i,j) = max{0,?jk=i Ak}的最大值
算法1:
int MaxSubseqSum1(int A[],int N) { int ThisSum,MaxSum = 0; int i,j,k; for(i=0;i < N;i++){ /*i是子列左端位置*/ for( j = i;j < N;j++){/*j是子列右端位置*/ ThisSum = 0;/*ThisSum是从A[i]到A[j]的子列和*/ for(k = i; k <= j; k++) ThisSum += A[k]; if(ThisSum > MaxSum)/*如果刚得到的这个子列和更大*/ MaxSum = ThisSum; /*则更新结果*/ } } retrun MaxSum }
复杂度 : T(N)=O(N3)
算法2:
int MaxSubseqSum2(int A[],int N) { int ThisSum,MaxSum = 0; int i,j; for(i=0;i < N;i++){ ThisSum = 0;/*ThisSum是从A[i]到A[j]的子列和*/ /*i是子列左端位置*/ for( j = i;j < N;j++){/*j是子列右端位置*/ ThisSum += A[j]; /*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/ if(ThisSum > MaxSum)/*如果刚得到的这个子列和更大*/ MaxSum = ThisSum; /*则更新结果*/ } } retrun MaxSum }
复杂度:T(N)=O(N2),最好想办法把算法改成nlogn,这样还要更快
算法3:份而治之,将数列一分为二,左边右边都用递归的方法,最后合成,
复杂度:T(N) = 2T(N/2) + cN, T(1) = O(1)=2[2T(N/22) + cN/2] + cN
=2kO(1) + ckN 其中N/2k = 1
=O(NlogN)
这仍然不是最快的算法
算法4:在线处理:在线的意思是指每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前的解。
int MaxSubswqSum4(iint A[],int N) { int i; ThisSum = MaxSum = 0; for(i = 0; i < N; i++){ ThisSum += A[i];/*向右累加*/ if(ThisSum > MaxSum) MaxSum = ThisSum;/*发现更大和则更新当前结果*/ else if(ThisSum < 0)/*如果当前子列和为负*/ ThisSum = 0;/*则不可能使后面的部分和增大,抛弃之*/ } return MaxSum; }
复杂度:T(N) = O(N)
原文:https://www.cnblogs.com/solaris-wwf/p/11997132.html