算法導論day2

最糟糕的是人們在生活中常常受到錯誤志向的阻礙而不自知,真到擺脫了那些阻礙時才能明白過來。萬事開頭難,但願可以persistence。

算法導論day2

函數的增加

漸近精確界記號:Θ(big-theta)

對於算法的運行時間表達式\(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)便可以表示上界也能夠表示下界。算法

漸近上界記號:\(O(big-oh)\)

定義:設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)。數組

漸近下界記號:\(\Omega(big-omega)\)

定義:設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

非漸近精確上界:o(small-oh)

定義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

非漸近精確下界:\(\omega(small-omega)\)

定義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): 存在正常數c1,c2和n0,使對全部的n>=n0,有0<=c1g(n)<=f(n)<=c2g(n) }
  • O(g(n))={ f(n): 存在正常數c和n0,使對全部n>=n0,有0<=f(n)<=cg(n) }
  • Ω(g(n))={ f(n): 存在正常數c和n0,使對全部n>=n0,有0<=cg(n)<=f(n) }
  • o(g(n))={ f(n): 對任意正常數c,存在常數n0>0,使對全部的n>=n0,有0<=f(n)<=cg(n) }
  • ω(g(n))={ f(n): 對任意正常數c,存在常數n0>0,使對全部的n>=n0,有0<=cg(n)<f(n) }
    例子:對於O來說,它是用來表示上界的,當用它做爲算法的最壞狀況運行時間的上界時,就有對任意輸入的運行時間的上界。咱們說「一個算法A的運行時間爲\(O(n^2)\),它表示的是說該算法運行時間的一個上界,適用於每一個輸入的運行時間。spa

    分治策略

    最大子數組問題

    尋找數組A的和最大的非空連續子數組的問題。只有當數組中包含負數時,最大子數組問題纔有意義。若是全部的數組元素都是非負的,最大子數組問題沒有任何難度,由於整個數組的和確定是最大的。
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

  1. 徹底處於子數組A[low..mid]中
  2. 徹底處於子數組A[mid+1..high]中
  3. 跨越了中點mid
    所以只要求出跨越中點mid的最大連續子數組的值,另外的左右子數組遞歸,最後比較三者的大小,便可得出最後的最大連續子數組。
  • 遞歸流程
    程序先執行left遞歸,直至知足low==high,返回left_result,接着執行right,當即返回right_result,可能會執行cross,返回cross_result,最後比較三者大小,返回最大值。(這是left遞歸最底層的執行過程)接着返回到left的上一層遞歸,此時的left_result就是剛剛比較的最大值,緊接着執行這一層的right,此時須要執行right遞歸,最後返回這一層的right_result(一樣是比較的最大值),可能也要執行cross返回cross_result,最後再比較三者大小並返回left的再上一層遞歸。如此循環,最後返回的就是整個數組的最大連續子數組。code

    矩陣乘法的Strassen算法

    矩陣相乘這一部分算法導論介紹了三個解決方法,分別是暴力法,直接遞歸分治算法以及Strassen算法。
    下面的代碼片斷是前兩種方法的實現。遞歸分治算法的難點主要在於構建子矩陣以及合成矩陣這兩方面。
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;
        }
}
相關文章
相關標籤/搜索