• 1.2 数据抽象


    练习

    1.2.1 编写一个Point2D的用例,从命令行接受一个整数N.在单位正方形中生成N个随机点,然后计算两点之间的最近距离.       /*查阅Point2D的API*/

    public class H1_2_01
    {
        public static void main(String[] args)
        {
            int N=1000;
            Point2D[] arr=new Point2D[N];
            for(int i=0;i<N;i++)
                arr[i]=new Point2D(Math.random(), Math.random());
    
            double mindis=Double.POSITIVE_INFINITY;  //mindis--store the minimum distance
            for(int i=0;i<N-1;i++)
                for(int j=i+1;j<N;j++)
                {
                    double dis=arr[i].distanceTo(arr[j]);
                    if(mindis>dis)
                        mindis=dis;
                }
            StdOut.printf("the minimum distance is: %.5f
    ",mindis);
        }
    }

    1.2.2 编写一个Interval1D的用例,从命令行接受一个整数N.从标准输入中读取N个间隔(每个间隔由一对double值定义)并打印出所有相交的间隔对

    public class H1_2_02
    {
        public static void main(String[] args)
        {
            int N=10;
            Interval1D[] arr=new Interval1D[N];
            for(int i=0;i<N;i++)
            {
                StdOut.println("please input an interval1D.");
                double lo=StdIn.readDouble();
                double hi=StdIn.readDouble();
                while(lo>hi)    //消除不合理的输入
                {
                    StdOut.println("the input is illegal, please input again.");
                    lo=StdIn.readDouble();
                    hi=StdIn.readDouble();
                }
                arr[i]=new Interval1D(lo, hi);
            }
            for(int i=0;i<N-1;i++)
                for(int j=i+1;j<N;j++)
                {
                    if(arr[i].intersects(arr[j]))
                        StdOut.printf("the interval %s is intersected to the interval %s
    ",arr[i].toString(),arr[j].toString());
                }
        }
    }

    1.2.3 编写一个Interval2D的用例,从命令行接受参数N、min和max.生成N个随机的2D间隔,其宽和高均匀的分布在单位正方形中的min和max之间.用StdDraw画出他们并打印出橡胶的间隔对的数量以及包含关系的间隔对数量

    public class H1_2_3
    {
        public static void main(String[] args)
        {
            int N=20;
            double min=0.05;
            double max=0.1;
            int containCnt=0;int intersectCnt=0;
            Interval2D[] arr=new Interval2D[N];
            Interval1D[] arrx=new Interval1D[N];
            Interval1D[] arry=new Interval1D[N];
            for(int i=0;i<N;i++)
            {
                double x=StdRandom.uniform(0.0,1-max);
                arrx[i]=new Interval1D(x, x+StdRandom.uniform(min, max));
                double y=StdRandom.uniform(0.0,1-max);
                arry[i]=new Interval1D(y, y+StdRandom.uniform(min,max));
                arr[i]=new Interval2D(arrx[i], arry[i]);
                StdDraw.setPenColor(StdDraw.BOOK_BLUE);
                arr[i].draw();
            }
            for(int i=0;i<N-1;i++)
                for(int j=i+1;j<N;j++)
                {
                    if(arr[i].intersects(arr[j]))
                    {
                        intersectCnt++;
                        if(iscontains(arrx[i],arry[i], arrx[j], arry[j]))
                            containCnt++;
                    }
                }
            StdOut.printf("the intersect interval2D=%d, the contain interval2D=%d
    ", intersectCnt,containCnt);
        }
        public static boolean iscontains(Interval1D x1,Interval1D y1,Interval1D x2,Interval1D y2)  //判断是否存在包含关系
        {
            if(x1.left()<=x2.left()&&x1.right()>=x2.right()&&y1.left()<=y2.left()&&y1.right()>=y2.right())
                return true;
            if(x2.left()<=x1.left()&&x2.right()>=x1.right()&&y2.left()<=y1.left()&&y2.right()>=y1.right())
                return true;
            return false;
        }
    }

    注:另一种解决思路是在Interval2D类中添加判断是否存在包含关系的实例函数

    1.2.4 主要考察字符串不可变---因此对字符串重新"赋值"其实是指向了新的对象而不是改变原有值

    1.2.6 编写一个程序检查两个给定的字符串s和t是否互为回环变位(如果字符串s中的字符循环移动任意位置之后能够得到另一个字符串t,那么s就被称为t的回环变位)    /*掌握字符串的灵活用法*/

    public class H1_2_06
    {
        public static void main(String[] args)
        {
            StdOut.println(cirRotation("ACTGACG", "TGACGAC"));
        }
        
        public static boolean cirRotation(String s,String t)
        {
            String temp=s+s;  //该语句起到很大的简便判断作用
            if(temp.indexOf(t)!=-1&&s.length()==t.length())
                return true;
            return false;
        }
    }

    作者网站上给出的答案:Solution: (s.length() == t.length()) && (s.concat(s).indexOf(t) >= 0)

    1.2.9 修改BinarySearch,使用Counter统计在查找中被检查的键的总数并在查找结束后打印该值.

    public class H1_2_09
    {
        public static void main(String[] args)
        {
            Counter cnt=new Counter("count");
            int[] arr={1,4,5,6,7,8,9};
            Arrays.sort(arr);
            int key=9;
            rank(key,arr,cnt);
            StdOut.println(cnt.toString());
        }
        
        public static int rank(int key,int[] a,Counter cnt)
        {
            int lo=0;
            int hi=a.length-1;
            while(lo<=hi)
            {
                cnt.increment();  //每次进入循环代表一次检查
                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;
        }
    }

    1.2.10 编写一个类VisualCounter,支持加一和减一操作.它的构造函数接受两个参数N和max,其中N指定了操作的最大次数,max指定了计数器的最大绝对值.作为副作用,用图形显示每次计数器变化后的值.

    先根据要求列出"需求"API     /*明确类所需要的数据,方法等*/

    VisualCounter(int N,int max) 构造函数
    increment() 加一操作
    decrement() 减一操作
    public class VisualCounter
    {
        private int cnt=0;
        private int opN=0;
        private int max;
        private int N;
        public VisualCounter(int N,int max)
        {
            this.N=N;
            this.max=max;
            StdDraw.setXscale(0,N);
            StdDraw.setYscale(-max-0.1,max+0.1);
            StdDraw.setPenColor(StdDraw.BOOK_BLUE);
        }
        
        public void increment()
        {
            if(cnt<max&&opN<N)
            {
                cnt++;
                opN++;    
                StdDraw.filledRectangle(opN-0.5, cnt/2.0, 0.9/2, Math.abs(cnt)/2.0); //采用柱状图体现变化后的值
            }
        }
        public void decrement()
        {
            if(-cnt<max&&opN<N)
            {
                cnt--;
                opN++;
                StdDraw.filledRectangle(opN-0.5, cnt/2.0, 0.9/2, Math.abs(cnt)/2.0);
            }
        }
        
        public static void main(String[] args)
        {
            int N=10;int max=5;
            VisualCounter vc=new VisualCounter(N, max);
            int i=0;
            while(i<N)
            {
                if(StdRandom.bernoulli(0.5))  //采用等可能出现进行测试
                    vc.increment();
                else
                    vc.decrement();
                i++;
            }
        }
    }

    1.2.11&1.2.12 根据Date的API实现一个SmartDate类型,在日期非法时抛出一个异常,并为SmartDate添加一个方法dayOfTheWeek(),为日期中每周的日返回Monday到Sunday中的适当值.(可以假定时间是21世纪)         /*此题可了解构造函数直接如何调用,闰年的判断,蔡勒公式判断星期以及抛出异常的使用~ 此题重要!*/

    Date的API如下

    SmartDate(int month,int day,int year) 创建一个日期
    SmartDate(String str) 创建一个日期
    int day()
    int month()
    int year()
    String dayOfTheWeek() 当日为星期几
    public class SmartDate
    {
        private int year;
        private int month;
        private int day;
        public SmartDate(int y,int m,int d)
        {
            if(!isIllegal(y,m,d))
                throw new IllegalArgumentException("illegal date!!");
            else
            {
                year=y;
                month=m;
                day=d;
            }
        }
        public SmartDate(String date)
        {
            String[] fields=date.split("/");
            int m=Integer.parseInt(fields[0]);
            int d=Integer.parseInt(fields[1]);
            int y=Integer.parseInt(fields[2]);
    //        this(y,m,d); ---不可行,必须要写在第一行,因此此处不可用
            if(!isIllegal(y,m,d))
                throw new IllegalArgumentException("illegal date!!");
            else
            {
                year=y;
                month=m;
                day=d;
            }
        }
        
        public int year()
        {
            return year;
        }
        public int month()
        {
            return month;
        }
        public int day()
        {
            return day;
        }
        public String toString()
        {
            return month()+"/"+day()+"/"+year();
        }
        //运用蔡勒公式---判断改日的星期
        public String dayOfWeek()
        {
            int w=(year/100/4-2*(year/100)+year%100+year%100/4+26*(month+1)/10+day-1)%7;
            switch(w)
            {
            case 1:
                return "Monday";
            case 2:
                return "Tuesday";
            case 3:
                return "Wednesday";
            case 4:
                return "Thursday";
            case 5:
                return "Friday";
            case 6:
                return "Saturday";
            default:
                return "Sunday";
            }
        }
        
        //判断是否合法
        private boolean isIllegal(int y,int m,int d)  //判断日期是否合法:三方面--年月日
        {
            if(y<1||m<1||m>12||d<0||d>31)
                return false;
            int[] monthOfDay={0,31,-1,31,30,31,30,31,31,30,31,30,31};
            if(isLeapYear(y))
                monthOfDay[2]=29;
            else
                monthOfDay[2]=28;
            if(monthOfDay[m]<d)
                return false;
            return true;
        }
        
        private boolean isLeapYear(int year)  //判断是否为闰年
        {
            if(year%100!=0&&year%4==0)
                return true;
            else if(year%100==0&&year%400==0)
                return true;
            else
                return false;
        }
        
        public static void main(String[] args)
        {
            SmartDate sd=new SmartDate(2015,9,1);
            StdOut.println(sd.toString()+"  "+sd.dayOfWeek());
        }
    }

    1.2.13&1.2.14 用我们对Date的实现作为模板实现Transaction类型           /*euqal()重载---一般分为①是否同引用②是否为空③类型是否相同④3同强转⑤内容是否同*/

    根据表1.2.6给出的TransactionAPI如下(去掉compareTo)

    Transaction(String who, SmartDate when, double amount) 创建一笔交易
    Transaction(String transaction) 创建一笔交易
    String  who() 客户名
    Date  when() 交易日期
    double  amount() 交易金额
    String  toString() 对象的字符串表示
    boolean  equals(Object that) 该笔交易和that是否相同

    public
    class Transaction { private String name; private SmartDate date; private double num; public Transaction(String who,SmartDate when,double amount) { name=who.toString(); date=new SmartDate(when.year(), when.month(), when.day()); num=amount; } public Transaction(String trans) { String[] fields=trans.split("\s+"); name=fields[0]; date=new SmartDate(fields[1]); num=Double.parseDouble(fields[2]); } public String who() { return name; } public SmartDate when() { return date; } public double amount() { return num; } public String toString() { return "name:"+name+", date:"+date.toString()+", amount:"+num; } public boolean equals(Object x) //判断是否相等 { if(this==x) return true; if(x==null) return false; if(this.getClass()!=x.getClass()) return false; Transaction that=(Transaction) x; return that.date.equals(date)&&that.amount()==num&&that.who()==name; } public static void main(String[] args) { SmartDate date=new SmartDate(1996,12,5); Transaction tran=new Transaction("Bob",date,1000); StdOut.println(tran.toString()); } }

    提高题

    1.2.15 文件输入.基于String的split()方法实现In中的静态方法readInts().

    public class H1_2_15
    {
        public static int[] readInts(String name)
        {
            In in=new In(name);
            String input=in.readAll();
            String[] words=input.split("\s+");
            int[] ints=new int[words.length];
            for(int i=0;i<words.length;i++)
                ints[i]=Integer.parseInt(words[i]);
            return ints;
        }
        
        public static void main(String[] args)
        {
            int[] ints=readInts("h1_2_15.txt");
            for(int a:ints)
                StdOut.printf("%d ",a);
        }
    }

    1.2.16 有理数.为有理数实现一个不可变数据类型Rational,支持加减乘除操作       /*从中思考如何自己来写出一个API大纲然后实现之*/

    Rational(int numerator, int denominator)  
    Rational  plus(Rational b) 该数与b之和
    Rational  minus(Rational b) 该数与b之差
    Rational  times(Rational b) 该数与b之积
    Ratioanl  divides(Rational b) 该数与b之商
    boolean  equals(Rational that) 该数与that相等吗
    String  toString() 对象的字符串表示
    public class Rational
    {
        private long numerator;
        private long denominator;
        
        public Rational(int numerator,int denominator)
        {
            if(denominator<0)     //为后续方便,始终将分母变为正数
            {
                numerator=-1*numerator;
                denominator=-1*denominator;
            }
            long cd=gcd(Math.abs(numerator),Math.abs(denominator));  //化为分数的最简形式
            this.numerator=numerator/cd;
            this.denominator=denominator/cd;
        }
        
        public long getnumerator()
        {
            return numerator;
        }
        
        public long getdenominator()
        {
            return denominator;
        }
        
        public Rational plus(Rational b)
        {
            long num=b.getnumerator();
            long den=b.getdenominator();
            long tempnum=num*denominator+numerator*den;
            long tempden=den*denominator;
            long cd=gcd(Math.abs(tempnum),Math.abs(tempden));
            this.numerator=tempnum/cd;
            this.denominator=tempden/cd;
            return this;
        }
        
        public Rational minus(Rational b)
        {
            long num=b.getnumerator();
            long den=b.getdenominator();
            long tempnum=numerator*den-num*denominator;
            long tempden=den*denominator;
            long cd=gcd(Math.abs(tempnum),Math.abs(tempden));
            this.numerator=tempnum/cd;
            this.denominator=tempden/cd;
            return this;
        }
        
        public Rational times(Rational b)
        {
            long num=b.getnumerator();
            long den=b.getdenominator();
            long tempnum=numerator*num;
            long tempden=den*denominator;
            long cd=gcd(Math.abs(tempnum),Math.abs(tempden));
            this.numerator=tempnum/cd;
            this.denominator=tempden/cd;
            return this;
        }
        
        public Rational divides(Rational b)
        {
            long num=b.getnumerator();
            long den=b.getdenominator();
            long tempnum=numerator*den;
            long tempden=num*denominator;
            long cd=gcd(Math.abs(tempnum),Math.abs(tempden));
            this.numerator=tempnum/cd;
            this.denominator=tempden/cd;
            return this;
        }
        
        public boolean equals(Rational that)
        {
            if(this==that)
                return true;
            if(that==null)
                return false;
            return this.numerator==that.getnumerator()&&this.denominator==that.getdenominator();
        }
        
        public String toString()
        {
            if(denominator==1)
                return numerator+"";
            else
                return numerator+"/"+denominator;
        }
        private long gcd(long x,long y)
        {
            if(y==0)
                return x;
            long temp=x%y;
            return gcd(y,temp);
        }
        
        
        public static void main(String[] args)
        {
            Rational rat1=new Rational(10, 30);
            Rational rat2=new Rational(2, 5);
            StdOut.printf("plus: %s
    ",rat1.plus(rat2).toString());
            StdOut.printf("minus: %s
    ",rat1.minus(rat2).toString());  //ps:此处rat1已经为+rat2后的值
            StdOut.printf("times: %s
    ",rat1.times(rat2).toString());
            StdOut.printf("divides: %s
    ",rat1.divides(rat2).toString());
            StdOut.printf("equals?: %s
    ",rat1.equals(rat2));
        }
    }

    1.2.18 累加器的方差. var()---计算方差,  stddev()---计算标准差      /*回顾1.1.34中内容---此处采用的求均值和方差的方式很好,记忆之*/

    public class Accumulator
    {
        private double m;  //m---均值
        private double s;  //s---总和
        private int N;     //N---个数
        public void addDataValue(double x)
        {
            N++;
            s=s+1.0*(N-1)/N*(x-m)*(x-m);  //见后续推导
            m=m+(x-m)/N;    //即(x-m)/N可以理解为将x与m的偏离程度平均分散给N个
        }
        public double mean()
        {
            return m;
        }
        public double var()
        {
            return s/(N-1);
        }
        public double stddev()
        {
            return Math.sqrt(this.var());
        }
    }


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

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

  • 相关阅读:
    (文章转载)GetTextMetrics与GetTextExtent的区别
    (文章转载)
    (文章转载)在刷新窗口时经常要调用重绘函数
    (文章转载)MCI编程
    Visual C#的Excel编程
    EXCEL中合并单元格
    Excel、Exchange 和 C# (摘要)
    C# 查询一个值方法ExecuteScalar()
    如何用C#在Excel中生成图表?
    javascript 常用方法
  • 原文地址:https://www.cnblogs.com/Tinyshine/p/4775168.html
Copyright © 2020-2023  润新知