『算法』读书笔记 1.1Java语法 - 练习代码总结

Algorithms Fourth Edition

 

Chapter 1

本章结构

1.1Java语法 练习部分

1.2数据抽象

1.3集合类抽象数据类型:背包 (Bags) 、队列 (Queues) 、栈 (Stacks)

1.4面向操作的抽象数据类型

1.5连通性问题-Case Study: Union - Find ADT

 

 

 

 

 

ex1.1.3 从命令行得到三个整数参数。如果他们都相等则打印equal,否则打印not equal

public class PrintThreeInt {
    
    public static void main(String[] args)
    {
        int N1 = Integer.parseInt(args[0]);
        int N2 = Integer.parseInt(args[1]);
        int N3 = Integer.parseInt(args[2]);

        String Notification = "equal";
         if (N1 != N2) Notification = "not equal";
         if (N2 != N3) Notification = "not equal";
         System.out.println(Notification);
     
    }
}

总结:注意不能用return来返回字符串;且声明为void的方法不能有返回值

 

 

ex1.1.5 如果double类型的变量x和y都严格位于0和1之间则打印true,否则打印false

public class IsDoubleInPeriod {
    public static void main(String args[])
    {
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        String Notification = "false";
        if ( 0 <= x && x <= 1 && 0 <= y && y <=1) Notification = "true";
        StdOut.println(Notification);
    }
}

总结:注意区间的表达,[0,1]应为0 <= x && x <= 1而不是0 〈= x <= 1

 

 

ex1.1.11 打印一个二维布尔数组的内容,其中使用*表示真,空格表示假。打印出行号和列号

public class PrintArray {
    
    public static void main(String args[])
    {
        boolean[][] a = {{true,false},{true,true,false}};
        for (int i = 0; i < a.length; i++)
            for (int j = 0; j < a[i].length; j++)
            {
                if (a[i][j] == true) 
                    System.out.println("a["+i+"]["+j+"]:"+"*");
                else System.out.println("a["+i+"]["+j+"]:"+" ");
          }
    }

总结:在二维数组中,读取每一行的长度可用a[i].length,然后再进行遍历

 

 

ex1.1.13 打印一个M行N列的二维数组的转置

public class ConvertArray {
    
    public static void main(String args[])
    {
        int[][] a = {{1,3},{2,2},{5,6}};
        int[][] result_a = new int[2][3];
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 3; j++)
            {
                result_a[i][j] = a[j][i];
                System.out.println("a["+i+"]["+j+"]:"+result_a[i][j]);
            }
    }
}

问题:如何实现交错数组的转置?

 

 

ex1.1.14 编写一个静态方法lg(),接受一个整型参数N,返回不大于log2N的最大整数。不使用Math库

public class MathLg {
    private static int lg(int N)
    {
        int product = 1;
        int x = -1;
        if (N < 1) throw new RuntimeException("Error, N should be larger than 0");
        else 
        while (product <= N) //*,把等于的情况也纳入进来,从而避免了在如23>5这种情况的自增导致输出结果为3的情况
        {
            product *= 2;
            x++;
        }

        return x;
    }
    
    public static void main(String args[])
    {
        int N = Integer.parseInt(args[0]);
        StdOut.print(lg(N));
    }
}

注意:计数器x从-1开始计数,同时需要考虑计数器在如23>5这种情况的自增,见*

 

 

 ex1.1.15 编写一个静态方法histogram(),接受一个整型数组a[]和一个整数M为参数并返回一个大小为M的数组,其中第i个元素为整数i在参数数组中出现的次数。如果a[]中的值均在0到M-1之间,返回数组中的所有元素之和应该和a.length相等

public class Histogram {
    
    private static void histogram(int[] a, int M)
    {
        int[] b = new int[M];
        if (M > a.length) System.out.println("We don't have enough data in the input array");
        //int count =0;
        for (int i = 0; i < M; i++)
        {
            int count =0;
            for (int j = 0; j < a.length; j++)
            {
                //if (a[j] < M)
                //{
                    if (i == a[j])         count++;
                //}
                
            }
            b[i] = count;
        }
        for (int i = 0; i < b.length; i++)
            StdOut.println("Value of element " + i + " is " + b[i]);
    }
    
    public static void main(String[] args)
    {
        int[] a = {1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,6,7,8,9};
        int M = 5;
        histogram(a, M);
    }
}

总结:

* 1.尽量使用面向对象的思维:一开始把打印数组部分放在主方法中,后来发现直接在histogram()实现更佳,同时也便于调试

* 2.覆盖各种情况是本题之关键:

     a.考虑M的值大于输入数组长度的情况;

     b.考虑M小于数组中某些元素的值时,如何处理这些数字,例如本例中可直接忽略不处理

* 3.计数器应该放在第一个循环中,这样才能在完成一次查找时(子循环)清空计数器

* 4.数组打印必须采用遍历的形式,直接println()得到的只是数组的索引

 

 

ex1.1.19 题中给了一个利用递归实现菲波纳契数列,要求开发一个更好的实现,用数组保存已经计算过的值

public class Fibonacci{
      
    public static long F(int N)
    {
        if (N == 0) return 0;
        if (N == 1) return 1;
        
        long[] f = new long[N+1];//'Cause we need to deal with f[N] and f[0], N+1 elements are necessary
        f[0] = 0;
        f[1] = 1;
        
        for (int i = 2; i <= N; i++)//i must calculate to N so that f[N] can be reached
        {
            f[i] = f[i-1] + f[i-2];
            
        }
        return f[N];
    }
     
    public static void main(String[] args)
    {
        for (int N = 0; N < 100; N++)
            StdOut.println(N + " " + F(N));
    }
}

总结:经过改进后的算法效率提升明显。注意:数列增长速度很快,int类型以及不能很好的满足需求,宜采用long或大数据类型

 

 

ex1.1.20 编写一个递归的静态方法计算ln(N!)的值

public class Calln {
    
    private static double ln(int N)
    {
        int product = 1;
        if (N == 0) return 0;
        if (N == 1) return 1;
         
        for (int i = 2; i <= N; i++)
            product *= i ;
        return Math.log(product); //Don't know whether ln(N!) can be solved in this way. 
    }
    
    public static void main(String[] args)
    {
        int N = Integer.parseInt(args[0]);
        double value = ln(N);
        StdOut.print(value);
    }
}

问题:在13行利用了Math.log函数库进行对数运算,如果不使用这个库应该如何处理?

 

 

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

public class StudentGrade {
    
     public static void main(String[] args)
     {
         //Read all data from Standard Input and store them in String s
         String[] s = StdIn.readStrings();
         
         //Deal with data by person
         int N = s.length / 3;
         for (int i = 0; i < N; i++)
         {
             String name = s[3*i];
             int mathGrade = Integer.parseInt(s[3*i+1]);
             int averageGrade = Integer.parseInt(s[3*i+2]);
             double percentage = (double)mathGrade / (double)averageGrade; //Pay attention to the conversion
             StdOut.printf("%s" + " | " + "%d" + " | " + "%d" + " | " + "%.3f\n", name, mathGrade, averageGrade, percentage); 
         }
     }
}

总结:

* 1.readStrings()的读取结果为字符串数组,凡是遇到空格或换行时自动创建新数组

* 2. 异常 ArrayIndexOutOfBoundsException Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.

* 3.整型除以整型结果仍为整型,即便是将结果赋值给double。必须先强制转换需要计算的整数。

 

 

ex1.1.24 从命令行接受两个参数,计算它们的最大公约数并打印出每次调用递归方法时的两个参数。

public class Euclid {
    
    private static int gcd(int p, int q)
    {
        System.out.println("p: " + p + ", q:" + q);
        if (q == 0) return p;
        int r = p % q;
        return gcd(q, r);
    }
     
    public static void main(String[] args)
    {
        int N1 = Integer.parseInt(args[0]);
        int N2 = Integer.parseInt(args[1]);
        int p = gcd(N1, N2);
        System.out.println("The largest common divisor is " + p);
    } 
}

 

 

ex1.1.23 为BinarySearch的测试用例添加一个参数:+打印出标准输入中不在白名单上的值;—则打印出标准输入中在白名单上的值

import java.util.Arrays;
public class BinarySearchNew {
    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         (key < a[mid]) hi = mid - 1;
            else if (key > a[mid]) lo = mid + 1;
            else                   return mid;
        }
        return -1;
    }
    public static void main(String[] args)
    {
        int[] whitelist = In.readInts(args[0]);
        String para = args[1]; //new parameter for determining whether to print values in the whitelist or not in the whihtlist
        Arrays.sort(whitelist);
        
        //ATTENTION: selective clause cannot be placed inside while loop
        //if the parameter is set as "+"
        if (para.equals("+"))
            while (!StdIn.isEmpty())
            {
                int key = StdIn.readInt();
                if (rank(key, whitelist) < 0)
                        StdOut.println(key);
                
            }
        
        //if the parameter is set as "-"
        else if (para.equals("-"))
            while (!StdIn.isEmpty())
            {
                int key = StdIn.readInt();
                if (rank(key, whitelist) > 0)
                        StdOut.println(key);
                
            }
    }
}

总结:

* 1.注意字符串的比较,不能直接使用 ==,因为此时比较的是两字符串的引用。应当采用String1.equals(String2)的形式比较两字符串的值

* 2.In.readInts(args[0])这种情况指的是标准输入从文件中读取数据

问题:readInts()方法是如何从文件中读取数据的?为什么一长串连续的数字会被分成两个数字为一组的数组,看相关的Javadoc发现它利用了字符串的split来分割数字,可是存储数字的文件中并没有出现任何制表符、空行、换行符或回车,不解

 

public static double[] readDoubles(String filename) {
        In in = new In(filename);
        String[] fields = in.readAll().trim().split("\\s+");
        double[] vals = new double[fields.length];
        for (int i = 0; i < fields.length; i++)
            vals[i] = Double.parseDouble(fields[i]);
        return vals;
    }

读取的数据文件内容类似:23287974317892409871267891234

posted @ 2012-12-10 12:18  Memphis Yip  阅读(2402)  评论(2编辑  收藏  举报