【分治思想】算法
将一个问题分解为与原问题类似但规模更小的若干子问题,递归地解这些子问题,而后将这些子问题的解结合起来构成原问题的解。这种方法在每层递归上均包括三个步骤:编程
【分治递归表达式】数组
*********优化划分阶段,下降 T(n)=aT(n/b) + f(n) 中的 a*********ide
这里咱们假设有两个大整数X、Y,分别设X=123四、Y=5678。如今要求X*Y的乘积,小学的算法就是把X与Y中的每一项去乘,可是这样的乘法所需的时间复杂度为O(n^2),效率低下,咱们能够尝试使用分治来解决。函数
XY = (A2n/2 + B)(C2n/2 + D)优化
= AC2n + (AD+BC)2n/2 + BDui
= AC2n + ((A-B)(D-C)+AC+BD)2n/2 + BDidea
【矩阵相乘的朴素算法 T(n) = Θ(n3)】spa
朴素矩阵相乘算法,思想明了,编程实现简单。时间复杂度是Θ(n^3)。伪码以下3d
1 for i ← 1 to n 2 do for j ← 1 to n 3 do c[i][j] ← 0 4 for k ← 1 to n 5 do c[i][j] ← c[i][j] + a[i][k]⋅ b[k][j]
【矩阵相乘的strassen算法 T(n)=Θ(nlog7) =Θ (n2.81)】
通常算法须要八次乘法,四次加法;算法效率是Θ(n^3);
鉴于上面的分治法方案没法有效提升算法的效率,要想提升算法效率,由主定理方法可知必须想办法将2中递归式中的系数8减小。Strassen提出了一种将系数减小到7的分治法方案,以下图所示。
咱们能够看到上面只有7次乘法和屡次加减法,最终达到下降复杂度为O( nlg7 ) ~= O( n2.81 );
SQUARE-MATRIX-MULTIPLY-RECURSIVE(A,B) n=A.rows let C be a new n*n matrix if n==1 c11=a11*b11 else partition A, B and C as in equation(1) C11=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A11,B11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A12,B21) C22=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A11,B12) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A12,B22) C21=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A21,B11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A22,B21) C22=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A21,B22) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A22,B22) return C
问题定义:
算法思想:
伪代码:
递归方程:
算法复杂度: T(n) = θ(n logn)
【归并排序】
归并排序是分治思想的典型应用,
划分策略:根据中间点将数组集合划分红两部分,不断递归
合并策略:比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;不然将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,而后再将另外一个有序表中剩余的元素复制到r中从下标k到下标t的单元。
MergeSort(A,i,j) Input: A[i,…,j] Output:排序后的A[i,…,j] 1. k ← (i+j)/2; 2. MergeSort(A,i,k); 3. MergeSort(A,k+1,j); 4. l←i; h ← k+1; t=i; //设置指针 5. While l≤k & h< j Do 6. IF A[l] < A[h] THEN B[t] ← A[l]; l ← l+1; t ← t+1; 7. ELSE B[t] ← A[h]; h ← h+1; t ← t+1; 8. IF l<k THEH //第一个子问题有剩余元素 9. For v ← l To k Do 10. B[t] ← A[v]; t ← t+1; 11. IF h<j THEN //第二个子问题有剩余元素 12. For v ← h To j Do 13. B[t] ← A[v]; t ← t+1; 14. For v ← i To j Do //将归并后的数据复制到A中 15. A[v] ← B[v];
复杂度分析: T(n)=2T(n/2)+O(n) T(n)=O(nlogn)
复习:归并排序具备以下特色:
【快速排序】
划分策略:选取一个记录做为枢轴,通过一趟排序,将整段序列分为两个部分,其中一部分的值都小于枢轴,另外一部分都大于枢轴。
递归策略:而后继续对这两部分继续进行排序,从而使整个序列达到有序。
合并策略:无操做
QuickSort(A,i,j) Input: A[i,…,j], x Output: 排序后的A[i,…,j] 1. temp←rand(i,j); //产生i,j之间的随机数 2. x ← A[temp]; //以肯定的策略选择x 3. k=partition(A,i,j,x); //用x完成划分 4. QuickSort(A,i,k); //递归求解子问题 5. QuickSort(A,k+1,j);
Partition(A,i,j,x)
1. low←i ; high ←j;
2. While( low< high ) Do
3. swap(A[low], A[high]);
4. While( A[low] < x ) Do
5. low←low+1;
6. While( A[low] < x ) Do
7. high←high-1;
8. return(high)
平均、最优的时间复杂度为O(nlogn),最差的时间复杂度为O(n^2)
平均的空间复杂度为O(logn),最差的空间复杂度为O(n)
排序的下界是:Ω(n log n)
【最大值最小值】
算法MaxMin(A) 输入: 数组A[i,…,j] 输出:数组A[i,…,j]中的max和min 1. If j-i+1 =1 Then 输出A[i],A[i],算法结束 2. If j-i+1 =2 Then 3. If A[i]< A[j] Then输出A[i],A[j];算法结束 4. k←(j-i+1)/2 5. m1,M1 ←MaxMin(A[i:k]); 6. m2,M2 ←MaxMin(A[k+1:j]); 7. m ←min(m1,m2); 8. M ←max(M1,M2); 9. 输出m,M
时间复杂度分析:T(n) = 3n/2 - 2
因此时间复杂度为:O( ⌊3n/2⌋ )
【中位数的线性时间选择算法】
Input: 数组A[1:n], 1≤i≤n Output: A[1:n]中的第i-大的数 1. for j←1 to n/5 2. InsertSort(A[(j-1)*5+1 : (j-1)*5+5]); 3. swap(A[j], A[[(j-1)*5+3]); 4. x ←Select(A[1: n/5], n/10 ); 5. k ←partition(A[1:n], x); 6. if k=i then return x; 7. else if k>i then retrun Select(A[1:k-1],i); 8. else retrun Select(A[k+1:n],i-k);
递归方程式:T(n) ≤ T( ⌈n/5⌉ ) +T(7n/10+6) + O(n)
时间复杂度:T(n) = O(n)