码迷,mamicode.com
首页 > 其他好文 > 详细

1.2 数据抽象

时间:2015-09-02 00:00:47      阅读:499      评论:0      收藏:0      [点我收藏+]

标签:

练习

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\n",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\n",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\n", 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\n",rat1.plus(rat2).toString());
        StdOut.printf("minus: %s\n",rat1.minus(rat2).toString());  //ps:此处rat1已经为+rat2后的值
        StdOut.printf("times: %s\n",rat1.times(rat2).toString());
        StdOut.printf("divides: %s\n",rat1.divides(rat2).toString());
        StdOut.printf("equals?: %s\n",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~

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

 

1.2 数据抽象

标签:

原文地址:http://www.cnblogs.com/Tinyshine/p/4775168.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!