1.1 基础编程模型

知识点

数据类型:整型、双精度实数类型、布尔型、字符型(16位)

语句:声明语句、赋值语句、条件语句、循环语句、调用和返回语句(调用即调用另一种方法,返回则从方法中返回)

数组:int a=new int[N]

静态方法:static修饰的方法(注意与实例方法的区分)

使用递归主要三点:①递归总有一个最简单的情况  ②递归调用总是去尝试一个规模更小的子问题  ③递归调用的父问题和尝试解决的子问题之间不应该有交集

外部库:系统标准库java.lang.*,导入的系统库(如java.util.Array),作者编写的库

字符串

输入输出:标准输入输出---StdOut库和StdIn库

重定向用到的库:In库和Out库(主要指与文件或网页之间的重定向)

标准绘图库:StdDraw库


练习

1.1.1 略

1.1.2 略

1.1.3 从命令行得到三个参数,如果他们相等打印equal,否则打印not equal     /*命令行参数的使用*/

public class H1_1_3
{
    public static void main(String args[])
    {
        int a1=Integer.parseInt(args[0]);
        int a2=Integer.parseInt(args[1]);
        int a3=Integer.parseInt(args[2]);
        if(a1==a2&&a2==a3)
            StdOut.println("equal");
        else
            StdOut.println("not equal");
    }
}

 1.1.4 略

1.1.5 略

1.1.6 

public class H1_1_6
{
    public static void main(String args[])
    {
        int f=0;
        int g=1;
        for(int i=0;i<=15;i++)
        {
            StdOut.printf("%d  ",f);
            f=f+g;       //f(i+1)=f(i)+g(i)
            g=f-g;       //g(i+1)=f(i+1)-g(i)=f(i)
        }                //combine the two eq: f(i+1)=f(i)+f(i-1).
    }
}

 打印结果:0  1  1  2  3  5  8  13  21  34  55  89  144  233  377  610 

1.1.7 略

1.1.8 略

1.1.9 将一个正整数N用二进制表示为转换为一个String类型的值s   /*体现了字符串的妙用*/

public class H1_1_09
{
    public static void main(String args[])
    {
        int N=20;
        StdOut.printf("%d=%s
",N,toBString(N));
    }
    
    public static String toBString(int N)
    {
        String s="";
        for(int n=N;n>0;n/=2)
            s=(n%2)+s;      //in this statement,the order of s and n%2 cann't be change!
        return s;
    }
}

 1.1.11 打印出一个二维布尔数组的内容,其中*---true, 空格---false, 打印行号和列号     /*二维数组的认识和使用*/

public class H1_1_11
{
    public static void main(String args[])
    {
        boolean[][] arr=new boolean[][]{{true,true,false},{false,false,true}};
        printBoolArray(arr);
    }
    
    public static void printBoolArray(boolean[][] arr)
    {
        int line=arr.length;
        int row=0;
        if(line==0)
            return;
        else
            row=arr[0].length;
        for(int i=0;i<=row;i++)
        {
            if(i==0)
                StdOut.printf("   ");
            else
                StdOut.printf(" %d ",i);
        }
        StdOut.println();
        for(int i=0;i<line;i++)
        {
            StdOut.printf(" %d ", i+1);
            for(boolean a: arr[i])
            {
                if(a==true)
                    StdOut.printf(" * ");
                else
                    StdOut.printf("   ");
            }
            StdOut.println();
        }
    }
}

 1.1.13 打印出一个M行N列的二维数组的转置(交换行和列)    /*二维数组的存储, 是否有更好的实现方式呢?*/

public class H1_1_13
{
    public static void main(String args[])
    {
        int[][] arr=new int[][]{{1,41,23},{12,41,51}};
        printTransArray(arr);
    }
    public static void printTransArray(int[][] arr)
    {
        int line=arr.length;
        int row=arr[0].length;
        int[][] trans=new int[row][line];
        for(int i=0;i<line;i++)
        {
            for(int j=0;j<row;j++)
                trans[j][i]=arr[i][j];
        }
        for(int[] a1:trans)
        {
            for(int a: a1)
                StdOut.printf("%5d ",a);
            StdOut.println();
        }
    }
}

 1.1.14 接受一个整型参数N, 返回不大于log2N的最大整数   /*静态方法的体现*/

public class H1_1_14
{
    public static void main(String args[])
    {
        StdOut.println(lg(24));
    }
    
    public static int lg(int N)
    {
        int count=0;
        while((N=N/2)>=1)
            count++;
        return count;
    }
}

1.1.15 静态方法histogram(), 接受一个整型数组a[]和一个整数M为参数并返回一个大小为M的数组, 其中第i个元素的值为整数i在参数数组中出现的次数    /*数组的运用*/

public class H1_1_15
{
    public static void main(String args[])
    {
        int[] arr=new int[]{1,4,5,1,2,4,6};
        int[] cnt=histogram(arr,6);
        StdOut.println(Arrays.toString(cnt));
    }
    
    public static int[] histogram(int[] arr,int m)
    {
        int[] a=new int[m];
        for(int i=0;i<arr.length;i++)
        {
            if(arr[i]<m)
                a[arr[i]]++;
        }
        return a;
    }
}

 1.1.16 给出exR1(6)的返回值   /*递归的具体要求及执行顺序*/

public class TestExample
{
    public static void main(String[] args)
    {
        String str=exR1(6);
        StdOut.println(str);
    }
    
    public static String exR1(int n)
    {
        if(n<=0)
            return "";
        return exR1(n-3)+n+exR1(n-2)+n;
    }
}

递归的情况(exR1->f):f(6)-->f(3)+6+f(4)+6  f(3)-->f(0)+3+f(1)+3  f(0)=""  f(1)=f(-2)+1+f(-1)+1=11   =>从而f(6)-->31136+f(4)+6

                                                                  f(4)-->f(1)+4+f(2)+4  f(1)=11  f(2)=f(-1)+2+f(0)+2=22  =>从而f(6)-->311361142246

1.1.19 Fibonacci函数的实现方法   /*了解递归的使用场合,以及在一些场合下对其的改进*/

public class H1_1_19
{
    public static void main(String[] args)
    {
        int N=50;
        Stopwatch watch=new Stopwatch();
        StdOut.println("best way:"+fibonacci2(N));
        double time1=watch.elapsedTime();
        StdOut.println(time1);
        long[] arr=new long[N+1];
        for(int i=0;i<arr.length;i++)
            arr[i]=-1;
        StdOut.println("better way:"+fibonacci3(N,arr));
        double time2=watch.elapsedTime();
        StdOut.println(time2-time1);
        StdOut.println("normal way:"+fibonacci1(50));
        double time3=watch.elapsedTime();
        StdOut.println(time3-time2);
    }
    
    public static long fibonacci1(int N)
    {
        if(N==0)
            return 0;
        if(N==1)
            return 1;
        return fibonacci1(N-1)+fibonacci1(N-2);
    }
    
    public static long fibonacci2(int N)
    {
        long[] store=new long[N+1];
        store[0]=0;
        if(N>=1)
            store[1]=1;
        for(int i=2;i<=N;i++)
            store[i]=store[i-1]+store[i-2];
        return store[N];
    }
    
    public static long fibonacci3(int N,long[] arr)
    {
        if(N==0)
            arr[0]=0;
        if(N==1)
            arr[1]=1;
        if(N>=2&&arr[N-1]!=-1&&arr[N-2]!=-1)
            arr[N]=arr[N-1]+arr[N-2];
        if(arr[N]!=-1)
            return arr[N];
        return fibonacci3(N-1, arr)+fibonacci3(N-2, arr);
    }
}

fibonacci2和fibonacci3哪一种方式更佳?  fibonacci2略快,但是两者的增长量级是相同的(因此差别不大)

1.1.21 按行读取数据,其中每行包含一个名字和两个整数.用printf打印一张表格,每行的若干列数据包含名字、两个整数和第一个整数除以第二个整数的结果(精确到小数点后三位)

/*重定向IO及printf的使用*/

public class H1_1_21
{
    public static void main(String args[]) throws NumberFormatException, IOException
    {
        //声明一个输入流
        FileInputStream fis=new FileInputStream("h1121.txt");
        //重定向
        System.setIn(fis);
        //读取System.in标准输入流中的内容
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in,"gb2312"));
        String line=null;
        while((line=br.readLine())!=null)
        {
            String[] sarr=line.split(" ");
            StdOut.printf("%10s %.3f
",line,Double.parseDouble(sarr[1])/Double.parseDouble(sarr[2]));
        }            
    }
}

为偷懒,采用输入重定向, 重定向知识点见:http://www.cnblogs.com/liunanjava/p/4307793.html

1.1.22 修改rank()递归方法重新实现BinarySearch并跟踪该方法的调用, 每当方法被调用时, 打印出它的参数lo和hi并按照递归的深度缩进   /*此处也可以采用静态变量来实现*/

public class H1_1_22
{
    public static void main(String args[])
    {
        int[] arr=new int[]{1,4,5,12,51,23,12,21,51,23,41};
        Arrays.sort(arr);
        int answer=rank(5,arr);
        if(answer==-1)
            StdOut.println("can not find!");
    }
    
    public static int rank(int key,int[] a)
    {
        return rank(key,a,0,a.length-1,0);
    }
    
    public static int rank(int key,int[] a,int lo,int hi,int height)
    {
        if(lo>hi)
            return -1;
        height++;
        for(int i=0;i<height;i++)
            StdOut.print("  ");
        StdOut.printf("%d-%d
",lo,hi);
        int mid=lo+(hi-lo)/2;
        if(key<a[mid])
            return rank(key,a,lo,mid-1,height);
        else if(key>a[mid])
            return rank(key,a,mid+1,hi,height);
        else
            return mid;
    }
}

1.1.24 给出使用欧几里得算法计算105和24的最大公约数的过程中的带的一些列p和q的值。扩展该算法中的代码得到一个程序Euclid,从命令行接受两个参数,计算它们的最大公约数并打印出每次调用递归方法时的两个参数,使用你的程序计算1 111 111和1 234 567的最大公约数   /*主要掌握最大公约数如何求解*/

public class H1_1_24
{
    public static void main(String args[])
    {
        int g=Euclid(1111111,1234567);
        StdOut.println(g);
    }
    
    public static int Euclid(int p,int q)
    {
        StdOut.printf("%10d %10d
",p,q);
        if(q==0)
            return p;
        int r=p%q;
        return Euclid(q, r);
    }
}

 1.1.25 使用数学归纳法证明欧几里得算法能够计算任意一对非负整数p和q的最大公约数   /*数学层面上的证明,important*/

证明:即证明等式 gcd(p,q)=gcd(q,p%q)成立    /*定义 a|b等价于b%a==0*/

    不妨令 k=gcd(p,q)  (即 k|p, k|q)       j=gcd(q,p%q)  (j|q, j|p%q)

        且根据   p=mq+(p%q)  可推导出  j|p

        ∴ j|p, j|q (但不一定是最大公约数)   ---> 即k>=j

  又∵ p%q=p-nq

        ∴ 同理可知   k|(p%q)

    ∴  k|q, k|(p%q) (但不一定是最大公约数)  ---> k<=j

  从而可知  k=j  得证


提高题

1.1.26 证明以下代码能够将a、b、c按照升序排序

if(a>b)
{    t=a;a=b;b=t;}
if(a>c)
{    t=a;a=c;c=t;}
if(b>c)
{    t=b;b=c;c=t;}

第一个条件语句保证了 a<b  第二个条件语句保证了 a<c  第三个条件语句保证了b<c

因此根据不等号的传递性可知 a<b<c 即得证

1.1.27 二项分布, 估计用以下代码计算binomial(30,10,0.25)将会产生的递归调用次数     /*掌握二项分布知识点及性质*/   /*与1.1.19进行对比,比较如何使用数组保存已知值---此题的方式更加容易理解和使用*/

public class H1_1_27
{
    public static long count=0;
    public static void main(String[] args)
    {
        StdOut.println(binomial_improved(30, 10, 0.25));
        StdOut.println(count);
        StdOut.println(binomial(30, 10, 0.25));
        StdOut.println(count);
    }
    
    //homework 1_1_27
    public static double binomial(int n,int k,double p)
    {
        count++;
        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);
    }
    
    //homework 1_1_27 improved
    public static double binomial_improved(int n,int k,double p)
    {
        double[][] restore=new double[n+1][k+1];
        for(int i=0;i<n+1;i++)
            for(int j=0;j<k+1;j++)
                restore[i][j]=-1;
        return binomial_improved(n,k,p,restore);
    }
    
    public static double binomial_improved(int n,int k,double p,double[][] restore)
    {
        count++;
        if(n==0&&k==0)
        {
            restore[n][k]=1.0;
            return 1.0;
        }
        if(n<0||k<0)
            return 0.0;
        else
        {
            if (restore[n][k]==-1)
                restore[n][k]=(1.0-p)*binomial_improved(n-1, k, p,restore)+p*binomial_improved(n-1, k-1, p,restore);
        }
        return restore[n][k];
    }
}

不采用数组存储计算过的值,将会有 261201548 此递归调用

其中运用到了帕斯卡恒等式: C(n+1,r)=C(n,r-1)+C(n,r)  --->(证明通过展开右边在合并即可)

根据帕斯卡恒等式可以得到以下结论:

 1.1.28 删除重复元素,修改BinarySearch类中的测试用例来删去排序之后白名单中的所有重复元素      /*删除重复元素方法*/

public class H1_1_28
{
    public static void main(String[] args) throws FileNotFoundException
    {
        @SuppressWarnings("deprecation")
        int[] whitelist=In.readInts(args[0]);
        Arrays.sort(whitelist);
        //重定向输出---使之输出到文件
        PrintStream ps=new PrintStream(new FileOutputStream("Out_28.txt"));
        System.setOut(ps);
        for(int i=0;i<whitelist.length;i++)
        {
            if(i==0)
                StdOut.println(whitelist[i]);
            if(i>0&&whitelist[i]!=whitelist[i-1])
                StdOut.println(whitelist[i]);
        }
    }
}

1.1.29 等值键.为BinarySearch类添加一个静态方法rank(),它接受一个键和一个整型有序数组(可能存在重复键)作为参数并返回数组中小于该键的元素数量,以及一个类似的方法count()来返回数组中等于该键的元素的数量.注意:如果i和j分别是rank(key,a)和count(key,a)的返回值,那么a[i...i+j-1]就是数组中所有和key相等的元素   /*计数的技巧:涉及去除重复元素和计算重复元素个数*/

public class H1_1_29
{
    public static void main(String[] args)
    {
        int[] a={1,1,4,5,6,7,7,8,8,8,23,25,25,25,25};
        Arrays.sort(a);
        int num=25;
        int lessnum=rank(num,a);
        int equalnum=count(num,a);
        if(lessnum==-1)
            StdOut.println("this key is not in array!");
        else
            StdOut.printf("the num less than %d is %d
",num,lessnum);
        StdOut.printf("the num equal to %d is %d
",num,equalnum);
    }
    
    public static int rank(int key,int[] a)
    {
        int lo=0;
        int hi=a.length-1;
        while(lo<=hi)
        {
            int mid=lo+(hi-lo)/2;
            if(a[mid]<key)
                lo=mid+1;
            else if(a[mid]>key)
                hi=mid-1;
            else
            {
                while(mid>=0&&a[mid]==key)  //delete the same num's count
                    mid--;
                return mid+1;
            }
        }
        return -1;
    }
    
    public static int count(int key,int[] a)
    {
        int lo=0;
        int hi=a.length-1;
        int cnt=0,temp;
        while(lo<=hi)
        {
            int mid=lo+(hi-lo)/2;
            if(a[mid]<key)
                lo=mid+1;
            else if(a[mid]>key)
                hi=mid-1;
            else
            {   //following is important!!!
                temp=mid;
                while(mid>=0&&a[mid--]==key)
                    cnt++;
                mid=temp;
                while(mid<a.length-1&&a[++mid]==key)
                    cnt++;
                return cnt;
            }
        }
        return 0;
    }
}

1.1.30 数组练习.编写一段程序,创建一个N*N的布尔数组a[][].其中当i和j互质时(没有相同因子),a[i][j]为true,否则为false     /*数组与gcd结合的应用*/

public class H1_1_30
{
    public static void main(String[] args)
    {
        int n=5;
        boolean[][] arr=new boolean[n][n];
        torf(arr,n);
        printArray(arr, n);
    }
    public static void printArray(boolean[][] arr,int n)
    {
        for(int i=0;i<=n;i++)
        {
            if(i==0)
                StdOut.printf("   ");
            else
                StdOut.printf(" %4d ",i);
        }
        StdOut.println();
        for(int i=0;i<n;i++)
        {
            StdOut.printf(" %2d ",i+1);
            for(int j=0;j<n;j++)
            {
                StdOut.printf("%6s",Boolean.toString(arr[i][j]));
            }
            StdOut.println();
        }
    }
    /*此处将数组视为从1开始,否则无法满足互质条件*/
    public static void torf(boolean[][] arr,int n)
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(gcd(i,j)==1||gcd(i,j)==0)
                    arr[i-1][j-1]=true;
                else
                    arr[i-1][j-1]=false;
            }
    }
    
    public static int gcd(int m,int n)
    {
        
        if(n==0)
            return m;
        int temp=m%n;
        return gcd(n,temp);
    }
}

1.1.31 随机连线.从命令行接受一个整数N和double值p(0到1之间)作为参数,在一个半径为0.05的圆上画出间距相等的N个点,然后将每对点按照概率p用灰线连接

/*核心在于模块化编程思想,将整个过程拆分成---画圆,取点,点的随机连线等模块,先分清楚再动手*/

public class H1_1_31
{
    public static void main(String[] args)
    {
        int N=10;
        double p=0.5;
        randomLink(N, p);
    }
    
    public static void randomLink(int n,double p)
    {
        double circleX=0.07;
        double circleY=0.07;
        double r=0.05;
        drawCircle(circleX, circleY, r);
        PointXY[] arr=drawNPoint(circleX, circleY, r, n);
        connectPoint(arr, p);
    }
    
    public static void drawCircle(double x,double y,double r)
    {
        StdDraw.setXscale(0,2*x);
        StdDraw.setYscale(0,2*y);
        StdDraw.setPenRadius(0.001);
        StdDraw.setPenColor(StdDraw.BOOK_RED);
        StdDraw.circle(x, y, r);
    }
    
    public static PointXY[] drawNPoint(double x,double y,double r,int n)
    {
        PointXY[] arr=new PointXY[n];
        for(int i=0;i<n;i++)
            arr[i]=new PointXY();
        StdDraw.setPenRadius(0.002);
        StdDraw.setPenColor(StdDraw.BLUE);
        for(int i=0;i<n;i++)
        {
            arr[i].x=x+r*Math.cos(i*2*Math.PI/n);
            arr[i].y=y+r*Math.sin(i*2*Math.PI/n);
            StdDraw.point(arr[i].x,arr[i].y);
        }
        return arr;
    }
    
    public static void connectPoint(PointXY[] arr,double p)
    {
        StdDraw.setPenRadius(0.001);
        StdDraw.setPenColor(StdDraw.GRAY);
        for(int i=0;i<arr.length;i++)
            for(int j=i+1;j<arr.length;j++)
            {
                if(StdRandom.bernoulli(p)==true)
                    StdDraw.line(arr[i].x, arr[i].y, arr[j].x, arr[j].y);
            }
    }

}

class PointXY
{
    double x;
    double y;
    public PointXY()
    {
        this.x=0;
        this.y=0;
    }
    public PointXY(double x,double y)
    {
        this.x=x;
        this.y=y;
    }
}

1.1.32 直方图.假设标准输入流中含有一系列double值.编写一段程序,从命令行接受一个整数N和两个double值l和r.将(l,r)分为N段并使用StdDraw画出输入流中的值落入每段的数量的直方图

/*数据划分与统计*/

public class H1_1_32
{
    public static void main(String[] args)
    {
        double l=1.0;double r=10.0;int n=30;
        double[] arr=new double[1000];
        for(int i=0;i<1000;i++)
            arr[i]=StdRandom.uniform(l,r);
        histogram(arr,l,r,n);
    }
    
    public static void histogram(double[] arr,double l,double r,int n)
    {
        double len=(r-l)/n;
        int[] arrnum=new int[n];
        int max=0;
        for(int i=0;i<arr.length;i++)  //统计每个区域落入的个数
        {
            if(arr[i]<r&&arr[i]>=l)
                arrnum[(int)((arr[i]-l)/len)]++;
        }
        for(int i=0;i<n;i++)
        {
            if(arrnum[i]>max)
                max=arrnum[i];    //用于确定绘图时y坐标的设置
        }
        StdDraw.setXscale(l,r);
        StdDraw.setPenColor(StdDraw.BOOK_BLUE);
        for(int i=0;i<n;i++)
        {
            double x=l+len/2+i*len;
            double y=arrnum[i]/2.0/(max+1);
            double rw=0.9*len/2;
            double rh=y;
            StdDraw.filledRectangle(x, y, rw, rh);
        }    
    }
}

1.1.33 矩阵库.编写一个Matrix库并实现以下API

static double dot(double[] x,double[] y) 向量点乘
static double[][] mult(double[][] a,double[][] b) 矩阵和矩阵之积
static double[][] transpose(double[][] a) 矩阵转置
static double[] mult(double[][] a,double[] x) 矩阵和向量之积
static double[] mult(double[] y,double[][] a) 向量和矩阵之积
public class Matrix
{
    public static void main(String[] args)
    {
        double[] x={1,3,4};
        double[][] y={{1,2},{2,3},{2,5}};
        StdOut.println(Arrays.toString(mult(x,y)));
    }
    
    /*向量点乘*/
    public static double dot(double[] x,double[] y)
    {
        double ret=0;
        if(x.length!=y.length)
            return Double.NaN;
        for(int i=0;i<x.length;i++)
            ret+=x[i]*y[i];
        return ret;
    }
    /*矩阵和矩阵之积*/
    public static double[][] mult(double[][] a,double[][] b)
    {
        int la=a.length,ra=0;
        if(a.length!=0)
            ra=a[0].length;
        int lb=b.length,rb=0;
        if(lb!=0)
            rb=b[0].length;
        double[][] ret=new double[la][rb];
        for(int i=0;i<la;i++)
        {
            for(int k=0;k<rb;k++)
                for(int j=0;j<ra;j++)
                    ret[i][k]+=a[i][j]*b[j][k];
        }
        return ret;
    }
    /*转置矩阵*/
    public static double[][] transpose(double[][] a)
    {
        int la=a.length,ra=0;
        if(la!=0)
            ra=a[0].length;
        double[][] ret=new double[ra][la];
        for(int i=0;i<la;i++)
            for(int j=0;j<ra;j++)
                ret[j][i]=a[i][j];
        return ret;
    }
    /*矩阵和向量之积*/
    public static double[] mult(double[][] a,double[] x)
    {
        int la=a.length,ra=0;
        if(la!=0)
            ra=a[0].length;
        double[] ret=new double[la];
        for(int i=0;i<la;i++)
            for(int j=0;j<ra;j++)
                ret[i]+=a[i][j]*x[j];
        return ret;
    }
    /*向量和矩阵之积*/
    public static double[] mult(double[] y,double[][] a)
    {
        int la=a.length,ra=0;
        if(la!=0)
            ra=a[0].length;
        double[] ret=new double[ra];
        for(int i=0;i<ra;i++)
            for(int j=0;j<la;j++)
                ret[i]+=y[j]*a[j][i];
        return ret;
    }
}

1.1.34 过滤.那些任务需要保存标准输入中所有值(YES)?那些可以被实现为一个过滤器且仅使用固定数量的变量和固定大小的数组(NO)?

  • 打印出最大和最小的数               NO---通过定义变量一个max和min
  • 打印出所有数的中位数               YES
  • 打印出第k小的数,k小于100        NO---通过一个长度为k的数组
  • 打印出所有数的平方和               NO---通过定义变量total
  • 打印出N个数的平均值                NO---通过定义sum和count
  • 打印出大于平均值的数的百分比    YES
  • 将N个数按照升序打印                YES
  • 将N个数按照随机顺序打印          YES

实验题

1.1.35 模拟掷骰子.

public class H1_1_35
{
    public static void main(String[] args)
    {
        int n=100000;
        double[] fact=diceProbability();
        double[] simulate=diceSimulate(n);
        StdOut.println("fact probability:");
        for(double f:fact)
            StdOut.printf("%.3f  ",f);
        StdOut.println();
        StdOut.println("simulate probability:");
        for(double s:simulate)
            StdOut.printf("%.3f  ",s);
        StdOut.println();
    }
    
    public static double[] diceProbability()  //准确概率
    {
        int sides=6;
        double[] dist=new double[2*sides+1]; //此处由于不用0下标,所以加1
        for(int i=1;i<=sides;i++)
            for(int j=1;j<=sides;j++)
                dist[i+j]+=1.0;
        for(int k=2;k<2*sides+1;k++)
            dist[k]/=36.0;
        return dist;
    }
    
    public static double[] diceSimulate(int n)  //模拟情况下概率
    {
        int sides=6;
        int num1=0,num2=0;
        double[] dist=new double[2*sides+1];
        for(int i=0;i<n;i++)
        {
            num1=StdRandom.uniform(1,7);
            num2=StdRandom.uniform(1,7);
            dist[num1+num2]+=1.0;
        }
        for(int k=2;k<2*sides+1;k++)
            dist[k]/=n;
        return dist;
    }
}

1.1.36 乱序检查. ShuffleTest接受参数M和N,将大小为M的数组打乱N次且在每次打乱之前都将数组重新初始化为a[i]=i.打印一个MxM的表格,对于所有的列j,行i表示的是i在打乱后落到j的位置的次数.若shuffle能产生预期效果,则数组中所有元素应该接近于N/M      /*对目标函数的检验*/

public class H1_1_36
{
    public static void main(String[] args)
    {
        shuffleTest(5,100000);
    }
    
    public static void shuffleTest(int m,int n)
    {
        int[] arr=new int[m];
        int[][] store=new int[m][m];
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
                arr[j]=j;
            shuffle(arr);
            for(int k=0;k<arr.length;k++)
                store[arr[k]][k]++;   //arr[k]落到k位置
        }
        for(int[] s1:store)
        {
            for(int s2:s1)
                StdOut.printf("%d ",s2);
            StdOut.println();
        }
    }
    
    public static void shuffle(int[] a)  //乱序排序
    {
        int n=a.length;
        for(int i=0;i<n;i++)  //将a[i]和a[i..n-1]中任意一个元素交换
        {
            int r=i+StdRandom.uniform(n-i);
            int temp=a[i];
            a[i]=a[r];
            a[r]=temp;
        }
    }
}

1.1.39 随机匹配.编写一个使用BinarySearch的程序,从命令行接受一个整型参数T,并会分别针对 N=103,104,105和106将以下实验运行T遍:生成两个大小为N的随机6位正整数数组并找出同时位于两个数组中的整数的数量.打印一个表格,对于每个N,给出T次实验中该数量的平均值         /*模块化编程(好像应该叫函数式编程)--划分清楚各个部分,理清思路*/

public class H1_1_39
{
    public static void main(String[] args)
    {
        test(100);
    }
    
    public static void test(int t)   //测试函数
    {
        double avg_cnt=0;
        for(int i=1000;i<=1000000;i*=10)
        {
            for(int k=0;k<t;k++)
            {
                avg_cnt+=creatTwoArray(i);
            }
            StdOut.printf("the test of num %d: the average common num is %.3f
",i,avg_cnt/t);
        }
    }
    
    public static int binarySearch(int key,int[] a)  //二分查找
    {
        int lo=0;
        int hi=a.length-1;
        while(lo<=hi)
        {
            int mid=lo+(hi-lo)/2;
            if(key<a[mid])
                hi=mid-1;
            else if(key>a[mid])
                lo=mid+1;
            else
                return mid;
        }
        return -1;
    }
    
    public static int creatTwoArray(int n)  //生成两个数组并返回相同整数数量
    {
        int[] arr1=new int[n];
        int[] arr2=new int[n];
        for(int i=0;i<n;i++)
        {
            arr1[i]=StdRandom.uniform(100000, 1000000);
            arr2[i]=StdRandom.uniform(100000, 1000000);
        }
        return commonNum(arr1, arr2);
    }
    
    public static int commonNum(int[] arr1,int[] arr2)  //寻找同时存在于两个数组中整数的数量
    {
        int cnt=0;
        Arrays.sort(arr1);
        for(int i=0;i<arr2.length;i++)
        {
            int key=binarySearch(arr2[i], arr1);
            if(key!=-1)
                cnt++;
        }
        return cnt;
    }
}

以上答案中错误和不合理之处希望大家指出O(∩_∩)O~

注:里面很多来源于《算法》作者给的库

原文地址:https://www.cnblogs.com/Tinyshine/p/4772656.html