1. 程式人生 > >演算法第四版學習(chapter1.1)

演算法第四版學習(chapter1.1)

這是我個人真正意義上的第一篇blog,今天我來講一下,我在這個暑假學習的一本書,演算法(第四版)。

書的樣子

 第一章主要講述了一些標準工具的用法,這本書提供了一個標準庫,我們可以在他的網上下載下來,或者我這裡也可以

連結: https://pan.baidu.com/s/1Y89qdn5SWQ3KQfiF08ruPw 密碼: xsc7

我所遇到的難題:

1.1.25:使用數學歸納法證明歐幾里得演算法可以計算任意一對非負整數p和q的最大公約數

//歐幾里得演算法的java實現
public  static int gcd(int p,int q){
    if(q==0) return p;
    int r = p%q;
    return gcd(q,r);
}

 其實歐幾里得演算法也可以叫做輾轉相除

我們可以先分析一下這個演算法,想要這個演算法通過,我們要證明

當p%q=r

gcd(p,q)=gcd(q,r)

因為p%q=r,所以p=q*k+r(k為自然數)

我們設p和q的公約數為d,則p可以表示為d*i1,卻可以表示為d*i2(i1,i2均為正整數)

得d*i1=d*i2*k+r—>r=d*(i1-i2*k),所以在該情況下r和q的公約數也是d

由於d並不是單指其中一個,在所有情況下,皆能使r=d*(i1-i2*k)

所以我們能說gcd(p,q)=gcd(q,r).

鄙人的證明若有問題,歡迎指出。

1.1.27 :二態分佈。估計用一下程式碼計算(100,50,0.25)將會產生的遞迴呼叫次數:

我們先來講一下二態分佈公式的原理,二態公式其實就是一種統計學手法,binomial(n,k,p)n是獨立個體的個數,k是需要被選上的個體,p是被選上的機率。b(n,k,p)=(1-p)*b(n-1,k,p)+p*b(n-1,k-1,p)的意思其實是n個人裡面選k個,p是被選上的概率,有兩個方向:①沒選上概率1-p,等待被選人數減一,需要選的人數不變②被選上了概率p,等待被選人數減一,需要選的人數-1,以此類推最後得出的結果其實是,當人被挑選的概率為p,在n個人裡面選剛好k個人的機率。

我一開始失了智,還想測一下執行時長,果然這種不要命的遞迴測不得,編譯器都崩掉了。

long l = System.currentTimeMillis();
System.out.println("開始"+l);
double binomial = day02.binomial(100, 50, 0.25);
long l1=System.currentTimeMillis();
System.out.println(binomial+"--耗時"+(l1-l));



public static double binomial(int N,int k,double p){
    if(N == 0 && k==0) return 1.0;
    if(N<0 || k<0) return 0.0;
    return (1.0-p)*binomial(N-1,k,p)+p*binomial(N-1,k-1,p);
}

      其實我們不難發現可以將它遞迴過程總結成公式b(N,k)=b(N-1,k)+b(N-1,k-1),那個p不影響遞迴,先不考慮,每次由一個式子進行兩次遞迴,遞迴後N-1,k不變或-1,當N,k都為0,或其一小於0就結束,由N來影響一共會有多少層遞迴呼叫,該題目N為100,N由100到99,呼叫兩次遞迴,產生兩個式子,這兩個式子也進行遞迴,各分成兩個,先不考慮k,當N從100到0,會有2+2^{2}+2^{4}。。+2^{100},約為1.26*10^{30},現在來考慮k,k來決定那些式子提前結束遞迴(說明一個道理,當需要的k個人被選完了,N多少都不管用了,減掉選人-k分支,不選人的k不變的分支可以繼續往下走),這個我就不太會算了大概就是,等大佬來教,知道遞迴為什麼會炸了吧,這每次遞迴往下索值,這款記憶體並不會釋放,等會計算機就記憶體溢位了,或者直接崩掉。

     現在來說一下怎麼去開進這個演算法,既然遞迴會炸,我們就不用遞迴了,改用迴圈來求,先給出我的程式碼。

public class day03 {
    public static double binomial(int N,int k,double p){
        //先定義一個數組,來儲存計算資料
        double[][] array=new double[N+1][k+1];
        //array[0][0]的意思是,有0個人供你選擇,從其總選中0個人的概率,那就必定是1啦
        array[0][0]=1.0;
        //現將從頭到尾都不選的這一列都給上值,而都選是不可能的,所以不初始化了
        for(int i=1;i<N+1;i++){
            array[i][0]=array[i-1][0]*(1-p);
        }
        //我來解釋一下這一段,先是逐層往下計算,因為這個問題有明顯的上下層關係
        //j在遍歷過程中不能大於能被選的人數,不能大於需要被選的人數,減少一些多餘的分支
        // array[i][j]就是有i個人選j個人的機率,有兩種情況可以達成,i-1人選j人後不選,i-1人選j-1人後選一個
        for(int i=1;i<N+1;i++){
            for(int j=1;j<N+1&&j<k+1;j++){
                array[i][j]=(1-p)*array[i-1][j]+p*array[i-1][j-1];
            }
        }
        //最後返回需要的情況的機率
        return array[N][k];
    }
}

1.1.28:陣列去重,方法太多了,不打算寫,什麼排序後set,什麼Arraylist的方法indexof檢查是否在Arraylist裡,再做新增,blablabla。。。

1.1.30:呼叫gcd,好吧,查最大公因子是不是1,沒什麼好說的了。

1.1.31:隨機連線,上程式碼吧,為了看起來至觀,我把不同的線分層了。

public static void randomLine(int N,double p){
        StdDraw.setXscale(0,N);
        StdDraw.setYscale(0,N*N);

        double count=0.0;
        for(int i=0;i<N+1;i++){
            for(int j=i+1;j<N+1;j++){
                if(StdRandom.random()<p){
                    StdDraw.line(i*0.5,count*4,j*0.5,count*4);
                    count+=0.5;
                }
            }
        }

    }

大概長這個樣子吧。

1.1.35:骰子問題:呼叫StdRandom生成一些隨機數就好了,沒什麼難度。

public static void dice(int i) {
        DecimalFormat df   = new DecimalFormat("######0.000");
        int N = 10;
        double count = 0;
        boolean flag = true;
        for(int j=1;j<=6;j++){
            for(int k=1;k<=6;k++){
                if(k+j==i){
                    count++;
                }
            }
        }
        double rate=count/36.0;
        System.out.println(df.format(rate));
        while (flag) {
            count=0.0;
            int x = N;
            while (x-- > 0) {
                int a = (int) (StdRandom.uniform(1, 6 + 1));
                int b = (int) (StdRandom.uniform(1, 6 + 1));
                if (a + b == i) {
                    count++;
                    //System.out.println(a + "  " + b);
                }
            }
            double rate1=count / (double) N;
            if(df.format(rate1).equals(df.format(rate))){
                System.out.println("find it"+N);
                flag=false;
            }else{
                System.out.println(N+"--"+df.format(rate1)+"--"+df.format(rate));
                N*=10;
            }
        }
    }

1.1.39隨機匹配:

public static void match(int T) {
        int t=T;
        int count3 = 0;
        int count4 = 0;
        int count5 = 0;
        int count6 = 0;
        ArrayList arrayList = new ArrayList();
        int[] q3=new int[1000];
        int[] q4=new int[10000];
        int[] q5=new int[100000];
        int[] q6=new int[1000000];

        while (t-- > 0) {
            for (int i = 0; i < 1000; i++) {
                int a = StdRandom.uniform(1000000, 10000000);
                q3[i]=a;
            }
            Arrays.sort(q3);
            for (int i = 0; i < 1000; i++) {
                int b = StdRandom.uniform(1000000, 10000000);
                if(day02.sort(q3,b)>-1){
                    count3++;
                }
            }
            System.out.println("go");
            arrayList.clear();
            for (int i = 0; i < 10000; i++) {
                int a = StdRandom.uniform(1000000, 10000000);
                q4[i]=a;
            }
            for (int i = 0; i < 10000; i++) {
                int b = StdRandom.uniform(1000000, 10000000);
                if(day02.sort(q4,b)>-1){
                    count4++;
                }
            }
            arrayList.clear();
            for (int i = 0; i < 100000; i++) {
                int a = StdRandom.uniform(1000000, 10000000);
                q5[i]=a;
            }
            for (int i = 0; i < 100000; i++) {
                int b = StdRandom.uniform(1000000, 10000000);
                if(day02.sort(q5,b)>-1){
                    count5++;
                }
            }
            arrayList.clear();
            for (int i = 0; i < 1000000; i++) {
                int a = StdRandom.uniform(1000000, 10000000);
                q6[i]=a;
            }
            for (int i = 0; i < 1000000; i++) {
                int b = StdRandom.uniform(1000000, 10000000);
                if(day02.sort(q6,b)>-1){
                    count6++;
                }
            }
        }
        System.out.println("10的三次方平均數"+count3/T);
        System.out.println("10的四次方平均數"+count4/T);
        System.out.println("10的五次方平均數"+count5/T);
        System.out.println("10的六次方平均數"+count6/T);
    }

這一塊的學習就先到此為止了,有不太明白的各位,可以在下面留言問我,我會盡快回答