对于算法的运行时间表达式\(T(n)=30n^4+20n^3+40n^2+46n+100\),当问题规模足够大的时候如n=100万,则算法的运行时间主要取决于表达式的第一项,因而,运行时间能够记为:\(T(n) \approx n^4\),即\(T(n)= \theta(n^4)\)。html
\(\theta\)的数学含义在于:对于全部的\(n>n_0\)时,函数f(n)乘上一个常量因子可等于g(n),则称g(n)是f(n)的一个渐进精确界。g(n)便可以表示上界也能够表示下界。算法
定义:设f(n)和g(n)是定义域为天然数集N上的函数。若存在正数c和\(n_0\),使得对一切\(n \geq n_0\)都有0≤f(n)≤cg(n)成立,则称f(n)的渐进的上界是g(n),记做f(n)=O(g(n))。通俗的说n知足必定条件范围内,函数f(n)的阶不高于函数g(n)。数组
定义:设f(n)和g(n)是定义域为天然数集N上的函数。若存在正数c和\(n_0\),使得对一切\(n \geq n_0\)都有0≤cg(n)≤f(n)成立,则称f(n)的渐进的下界是g(n),记做f(n)=Ω(g(n))。通俗的说n知足必定条件范围内,函数f(n)的阶不低于函数g(n)。app
定义1:设f(n)和g(n)是定义域为天然数集N上的函数。若对于任意正数c,都存在\(n_0\),使得对一切\(n \geq n_0\)都有0≤f(n)<cg(n)成立,则称f(n)的渐进的非紧确上界是g(n),记做f(n)=o(g(n))。通俗的说n知足必定条件范围内,函数f(n)的阶低于函数g(n)。
定义2:设f(n)和g(n)是定义域为天然数集合的函数。若是\(\lim_{x\to \infty} \frac{f(n)}{g(n)}=0\),那么f(n)=o(g(n))。通俗理解为f(n)低于g(n)的阶。dom
定义1:设f(n)和g(n)是定义域为天然数集N上的函数。若对于任意正数c,都存在\(n_0\),使得对一切\(n \geq n_0\)都有0≤cg(n)<f(n)成立,则称f(n)的渐进的非紧确下界是g(n),记做f(n)=ω(g(n))。通俗的说n知足必定条件范围内,函数f(n)的阶高于函数g(n)。
定义2:设f(n)和g(n)是定义域为天然数集合的函数。若是\(\lim_{x\to \infty} \frac{f(n)}{g(n)}=\infty\),那么f(n)=o(g(n))。通俗理解为f(n)高于g(n)的阶。ide
ω(g(n))={ f(n): 对任意正常数c,存在常数n0>0,使对全部的n>=n0,有0<=cg(n)<f(n) }
例子:对于O来说,它是用来表示上界的,当用它做为算法的最坏状况运行时间的上界时,就有对任意输入的运行时间的上界。咱们说“一个算法A的运行时间为\(O(n^2)\),它表示的是说该算法运行时间的一个上界,适用于每一个输入的运行时间。spa
package com.JackeyZz.day2; class Result{ int low; int high; int sum; } public class divide { public static void main(String[] args) { int n=(int) (Math.random()*10+1); int[] arr=new int[n]; System.out.println("产生的"+n+"个随机数以下:"); for(int i=0;i<n;i++){ int x=(int) (Math.random()*10+1); arr[i]=(int) ((int) (Math.random()*100)*Math.pow(-1, x)); System.out.print(arr[i]+" "); } System.out.println(""); System.out.println("输出的最大子数组为:"); //int[] arr1={2,-1,8,9,-5,10,5,1,-8,4,-5,-6,-3,7}; //int[] arr1={5,-7,3,4,5,6,8,-10,-12}; Result result=new Result(); //result=find_max_crossing_subarray(arr1, 0, 6, arr1.length-1); result=find_maximum_subarray(arr, 0, arr.length-1); System.out.println(result.low+" "+result.high+" "+result.sum); } public static Result find_max_crossing_subarray(int[] arr, int low,int mid,int high){ Result result = new Result(); int left_sum=(int) Double.NEGATIVE_INFINITY; int right_sum=(int) Double.NEGATIVE_INFINITY; int sum = 0; for(int i=mid;i>=low;i--){ sum=sum+arr[i]; if(sum>left_sum){ left_sum=sum; result.low=i; } } sum=0; for(int j=mid+1;j<=high;j++){ sum=sum+arr[j]; if(sum>right_sum){ right_sum=sum; result.high=j; } } result.sum=left_sum+right_sum; return result; } public static Result find_maximum_subarray(int[] arr,int low,int high){ int mid; Result left_result = new Result(); Result right_result = new Result(); Result cross_result = new Result(); if(high==low){ left_result.low=low; left_result.high=low; left_result.sum=arr[low]; return left_result; } else{ mid=(low+high)/2; left_result=find_maximum_subarray(arr, low, mid); right_result=find_maximum_subarray(arr, mid+1, high); cross_result=find_max_crossing_subarray(arr, low, mid, high); if(left_result.sum>=right_result.sum && left_result.sum>=cross_result.sum){ return left_result; } else if(right_result.sum>=left_result.sum && right_result.sum>=cross_result.sum){ return right_result; } else{ return cross_result; } } } }
很容易就知道数组A的任何连续子数组A[i..j]必然处于如下三种状况:.net
递归流程
程序先执行left递归,直至知足low==high,返回left_result,接着执行right,当即返回right_result,可能会执行cross,返回cross_result,最后比较三者大小,返回最大值。(这是left递归最底层的执行过程)接着返回到left的上一层递归,此时的left_result就是刚刚比较的最大值,紧接着执行这一层的right,此时须要执行right递归,最后返回这一层的right_result(一样是比较的最大值),可能也要执行cross返回cross_result,最后再比较三者大小并返回left的再上一层递归。如此循环,最后返回的就是整个数组的最大连续子数组。code
package com.JackeyZz.day2; public class divide1 { public static void main(String[] args) { int[][] A=new int[4][4]; int[][] B=new int[4][4]; System.out.println("产生的8*8矩阵A:"); for(int i=0;i<A.length;i++){ for(int j=0;j<A[0].length;j++){ A[i][j]=(int) (Math.random()*10+1); System.out.print(A[i][j]+" "); } System.out.println(""); } System.out.println("产生的8*8矩阵B:"); for(int i=0;i<B.length;i++){ for(int j=0;j<B[0].length;j++){ B[i][j]=(int) (Math.random()*10+1); System.out.print(B[i][j]+" "); } System.out.println(""); } System.out.println("暴力法矩阵相乘结果:"); int[][] result1=new int[4][4]; result1=Matrix_multiply(A, B, 4); for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ System.out.print(result1[i][j]+" "); } System.out.println(""); } System.out.println("分治法矩阵相乘结果:"); int[][] result=null; result=square_matrix_multiply_recursive(A, B, 4); for(int i=0;i<result.length;i++){ for(int j=0;j<result[0].length;j++){ System.out.print(result[i][j]+" "); } System.out.println(""); } } //暴力求解矩阵相乘 public static int[][] Matrix_multiply(int[][] A,int[][] B,int n){ int[][] result=new int[n][n]; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ result[i][j]=0; for(int k=0;k<n;k++){ result[i][j]+=A[i][k]*B[k][j]; } } } return result; } //递归求解矩阵乘法 public static int[][] square_matrix_multiply_recursive(int[][] A, int[][] B,int n){ int[][] result=new int[n][n]; if(n==2){ result=Matrix_multiply(A, B, n); return result; } if(n>2){ int m=n/2; int[][] A11=QuarterMatrix(A, n, 1); int[][] A12=QuarterMatrix(A, n, 2); int[][] A21=QuarterMatrix(A, n, 3); int[][] A22=QuarterMatrix(A, n, 4); int[][] B11=QuarterMatrix(B, n, 1); int[][] B12=QuarterMatrix(B, n, 2); int[][] B21=QuarterMatrix(B, n, 3); int[][] B22=QuarterMatrix(B, n, 4); int[][] result11=QuarterMatrix(result, n, 1); int[][] result12=QuarterMatrix(result, n, 2); int[][] result21=QuarterMatrix(result, n, 3); int[][] result22=QuarterMatrix(result, n, 4); //result=square_matrix_multiply_recursive(A11, B11, m); result11=AddMatrix(square_matrix_multiply_recursive(A11, B11, m), square_matrix_multiply_recursive(A12, B21, m), m); result12=AddMatrix(square_matrix_multiply_recursive(A11, B12, m), square_matrix_multiply_recursive(A12, B22, m), m); result21=AddMatrix(square_matrix_multiply_recursive(A21, B11, m), square_matrix_multiply_recursive(A22, B21, m), m); result22=AddMatrix(square_matrix_multiply_recursive(A21, B12, m), square_matrix_multiply_recursive(A22, B22, m), m); result=TogetherMatrix(result11, result12, result21, result22, m); } return result; } //获取矩阵的四分之一,并返回子矩阵 public static int[][] QuarterMatrix(int[][] P,int n,int num){ int row=n/2; int cols=n/2; int[][] result=new int[row][cols]; switch(num){ case 1:{ for(int i=0;i<row;i++){ for(int j=0;j<cols;j++){ result[i][j]=P[i][j]; } } break; } case 2:{ for(int i=0;i<row;i++){ for(int j=0;j<n-cols;j++){ result[i][j]=P[i][j+cols]; } } break; } case 3:{ for(int i=0;i<n-row;i++){ for(int j=0;j<cols;j++){ result[i][j]=P[i+row][j]; } } break; } case 4:{ for(int i=0;i<n-row;i++){ for(int j=0;j<n-cols;j++){ result[i][j]=P[i+row][j+cols]; } } break; } default: break; } return result; } //矩阵相加 public static int[][] AddMatrix(int[][] A,int[][] B,int n){ int[][] result=new int[n][n]; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ result[i][j]=A[i][j]+B[i][j]; } } return result; } //整合矩阵 public static int[][] TogetherMatrix(int[][] a,int[][] b, int[][] c,int[][] d,int n){ int[][] result=new int[2*n][2*n]; for(int i=0;i<2*n;i++){ for(int j=0;j<2*n;j++){ if(i<n){ if(j<n){ result[i][j]=a[i][j]; } else{ result[i][j]=b[i][j-n]; } } else{ if(j<n){ result[i][j]=c[i-n][j]; } else{ result[i][j]=d[i-n][j-n]; } } } } return result; } }
Strassen算法的核心思想是令递归树稍微不那么茂盛一点,即只递归进行7次而不是8次n/2*n/2矩阵的乘法,所以前两种算法的运行时间是\(O(n^3)\),而Strassen算法的运行时间是\(O(n^{2.81})\)。
Strassen算法的公式以下:
\(S_1=B_{12}-B_{22}\) \(S_2=A_{11}+A_{12}\) \(S_3=A_{21}+A_{22}\)
\(S_4=B_{21}-B_{11}\) \(S_5=A_{11}+A_{22}\) \(S_6=B_{11}+B_{22}\)
\(S_7=A_{12}-A_{22}\) \(S_8=B_{21}+B_{22}\) \(S_9=A_{11}-A_{21}\)
\(S_{10}=B_{11}+B_{12}\)
\(P_1=A_{11}*S_1\) \(P_2=S_{2}*B_{22}\) \(P_3=S_3*B_{11}\) \(P_4=A_{22}*S_4\) \(P_5=S_5*S_6\) \(P_6=S_7*S_8\) \(P_7=S_9*S_{10}\)
\(C_{11}=P_5+P_4-P_2+P_6\) \(C_{12}=P_1+P_2\) \(C_{21}=P_3+P_4\) \(C_{22}=P_5+P_1-P_3-P_7\)
实现的代码以下:
package com.JackeyZz.day2; public class divide2 { public static void main(String[] args) { int[][] A=new int[4][4]; int[][] B=new int[4][4]; System.out.println("产生随机矩阵A:"); for(int i=0;i<A.length;i++){ for(int j=0;j<A[0].length;j++){ A[i][j]=(int) (Math.random()*10+1); System.out.print(A[i][j]+" "); } System.out.println(""); } System.out.println("产生的随机矩阵B:"); for(int i=0;i<B.length;i++){ for(int j=0;j<B[0].length;j++){ B[i][j]=(int) (Math.random()*10+1); System.out.print(B[i][j]+" "); } System.out.println(""); } System.out.println("暴力法矩阵相乘结果:"); int[][] result1=new int[4][4]; result1=matrix_multiply(A, B, 4); for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ System.out.print(result1[i][j]+" "); } System.out.println(""); } System.out.println("Strassen产生的矩阵相乘:"); int[][] result=null; result=strassen_matrix(A, B, 4); for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ System.out.print(result[i][j]+" "); } System.out.println(""); } } public static int[][] strassen_matrix(int[][] A,int[][] B,int n){ int[][] result=new int[n][n]; if(n==2){ result=matrix_multiply(A, B, n); return result; } if(n>2){ int m=n/2; int[][] S1=null; int[][] S2=null; int[][] S3=null; int[][] S4=null; int[][] S5=null; int[][] S6=null; int[][] S7=null; int[][] S8=null; int[][] S9=null; int[][] S10=null; int[][] P1=null; int[][] P2=null; int[][] P3=null; int[][] P4=null; int[][] P5=null; int[][] P6=null; int[][] P7=null; int[][] A11=QuarterMatrix(A, n, 1); int[][] A12=QuarterMatrix(A, n, 2); int[][] A21=QuarterMatrix(A, n, 3); int[][] A22=QuarterMatrix(A, n, 4); int[][] B11=QuarterMatrix(B, n, 1); int[][] B12=QuarterMatrix(B, n, 2); int[][] B21=QuarterMatrix(B, n, 3); int[][] B22=QuarterMatrix(B, n, 4); int[][] result1=QuarterMatrix(result, n, 1); int[][] result2=QuarterMatrix(result, n, 2); int[][] result3=QuarterMatrix(result, n, 3); int[][] result4=QuarterMatrix(result, n, 4); S1=Addmatrix(B12, B22, m, -1); S2=Addmatrix(A11, A12, m, 1); S3=Addmatrix(A21, A22, m, 1); S4=Addmatrix(B21, B11, m, -1); S5=Addmatrix(A11, A22, m, 1); S6=Addmatrix(B11, B22, m, 1); S7=Addmatrix(A12, A22, m, -1); S8=Addmatrix(B21, B22, m, 1); S9=Addmatrix(A11, A21, m, -1); S10=Addmatrix(B11, B12, m, 1); P1=strassen_matrix(A11, S1, m); P2=strassen_matrix(S2, B22, m); P3=strassen_matrix(S3, B11, m); P4=strassen_matrix(A22, S4, m); P5=strassen_matrix(S5, S6, m); P6=strassen_matrix(S7, S8, m); P7=strassen_matrix(S9, S10, m); result1=Addmatrix(Addmatrix(Addmatrix(P5, P4,m, 1), P2, m, -1), P6, m, 1); result2=Addmatrix(P1, P2, m, 1); result3=Addmatrix(P3, P4, m, 1); result4=Addmatrix(Addmatrix(Addmatrix(P5, P1,m, 1), P3, m, -1), P7, m, -1); result=TogetherMatrix(result1, result2, result3, result4, m); } return result; } //暴力矩阵相乘 public static int[][] matrix_multiply(int[][] A,int[][] B,int n){ int[][] result=new int[n][n]; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ result[i][j]=0; for(int k=0;k<n;k++){ result[i][j]+=A[i][k]*B[k][j]; } } } return result; } //划分子矩阵 public static int[][] QuarterMatrix(int[][] p,int n,int num){ int rows=n/2; int cols=n/2; int[][] result=new int[rows][cols]; switch(num){ case 1:{ for(int i=0;i<rows;i++){ for(int j=0;j<cols;j++){ result[i][j]=p[i][j]; } } break; } case 2:{ for(int i=0;i<rows;i++){ for(int j=0;j<n-cols;j++){ result[i][j]=p[i][j+cols]; } } break; } case 3:{ for(int i=0;i<n-rows;i++){ for(int j=0;j<cols;j++){ result[i][j]=p[i+rows][j]; } } break; } case 4:{ for(int i=0;i<n-rows;i++){ for(int j=0;j<n-cols;j++){ result[i][j]=p[i+rows][j+cols]; } } break; } default:break; } return result; } //矩阵相加减 public static int[][] Addmatrix(int[][] A,int[][] B,int n,int Bmark){ int[][] result=new int[n][n]; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ result[i][j]=A[i][j]+B[i][j]*Bmark; } } return result; } //整合矩阵 public static int[][] TogetherMatrix(int[][] a,int[][] b, int[][] c,int[][] d,int n){ int[][] result=new int[2*n][2*n]; for(int i=0;i<2*n;i++){ for(int j=0;j<2*n;j++){ if(i<n){ if(j<n){ result[i][j]=a[i][j]; } else{ result[i][j]=b[i][j-n]; } } else{ if(j<n){ result[i][j]=c[i-n][j]; } else{ result[i][j]=d[i-n][j-n]; } } } } return result; } }