Processing math: 100%

Project 2 基本类型与控制流

本次作业你将熟悉 Java 的基本类型 (primitive type), 表达式 (expression) 和控制结构 (control flow). 这些“面向过程”的方法是实现“面向对象”编程的基础. 另一方面, 你将复习模块化编程 (modular programming): 练习如何定义, 使用静态函数, 使用静态类编写一个简单的库. 希望此次作业能够帮助你了解 Java 的基础语法, 特别是它与 C 语言的区别. 同时, 希望通过强调“模块化”的概念, 为今后学习面向对象的设计打下基础.

基本类型的封装 (Wrappers of primitive types)

Java 为一些基本类型提供了封装 (Wrapper). 通过封装, Java 可以提供更丰富的面向的基本类型操作. 以下我们以整型为例说明如何使用这些基本类型的封装. 考虑一个32位整型变量

int a = 0;

用户可以对 a 进行加法, 乘法等运算. 但对一些较复杂的操作, 仍需要自行实现. 例如, 给定一个由数字组成的字符串 (“12235”), 将其转换成对应的整数 (问题: C 语言这个功能是如何实现?). 为了更方便用户使用, Java 将整型封装成为 Integer 类, 并在其中提供了一些针对整型的复杂操作. 例如, 为了将字符串转换成为整型, Integer 类提供了静态方法 parseInt():

String s = "12235";
int a = Integer.parseInt(s);
System.out.println(a == 12235);

又如, Integer 类提供了方法 toBinaryString(), 返回整形变量的二进制表示字符串:

int a = 11235;
String s = Integer.toBinaryString(a):
System.out.println(s);

事实上, 除了使用 Integer 类的静态方法外, 我们也可以使用 Integer 类的对象: Integer a = new Integer(11235);. 在作为函数参数时, 或者在赋值表达式中, Integer 对象和 int 可以通用. 例如对于上面的 Integer 对象 a, 我们可以将其赋值给 int 型变量 b int b = a;, 反之亦然. Java 编译器提供了这些情况下 int 到 Integer 对象的自动转换 (称为 autoboxing), 以及 Integer 对象到 int 的转换 (称为 unboxing). 关于 autoboxing 和 unboxing 可以参考这里.

关于 Integer 类的详细文档在这里. 除了整型外, 对于一些其他基本类型也有类似的封装: Boolean, Byte, Character, Double, Float, Long, Short.

随机数

我们可以使用 Math 包中的 random 方法产生 0 到1 间的随机数:

double r = Math.random();

例如, 以下代码将以概率 p 输出1, 以概率 1-p 输出0:

double r = Math.random();
if (r < p)
return 1;
else
return 0;

Random 类 也提供了产生随机数的接口.

##实验内容

基本类型和控制语句

  1. 以下表达式是否能够通过编译? 如果能够通过, 表达式的类型是什么? 表达式的值是什么? 请尝试解释原因.
  2. 假设int a = 2147483647; (即, Integer.MAX_VALUE). 请问以下语句的输出值是什么? 并解释原因.

    System.out.println(a);
    System.out.println(a + 1);
    System.out.println(2 - a);
    System.out.println(-2 - a);
    System.out.println(2 * a);
    System.out.println(4 * a);
  3. 函数Math.sqrt(double t) 计算一个数的平方根. 表达式Math.sqrt(2)*Math.sqrt(2) == 2的值是什么?

  4. 给定命令行参数 x1, y1, x2, y2. 计算平面上的点 (x1, y1) 和 (x2, y2) 的距离.

  5. 计算函数 logx,x,xlogx,x2,x3x=1,2,4,8,16,...,2048 处的值. 并比较它们的增长速度.

  6. 使用牛顿法计算平方根. 对于可导函数 f(x), 牛顿法用于计算 f 的零点 (f(x)=0). 令 f(x)t 的导数为 f(t). 给定初始值 x0, 首先计算过点 (x0,f(x0)), 斜率为 f(x0) 的直线与x轴的交点, 令该点为 x1. 对 x1, 计算过点 (x1,f(x1)), 斜率为f(x1)的直线与x轴的焦点, 令其为x2. 重复以上过程直到得到点 xn 使得 f(xn)=0 (过程参见1). 计算 c 等价于找函数 f(x)=x2c 的零点.

  7. 给定5个整数 (通过命令行参数), 找出它们的中位数 (即第3大的数).
  8. 给定5个整数 (通过命令行参数), 找出它们的中位数, 要求使用“比较”操作的次数不超过6次. 是否存在算法能够使用更少的比较操作找到中位数?
  9. 一对夫妻希望得到男孩和女孩. 他们不停的生孩子, 直到一个不同性别的孩子出生. 假设生男孩和女孩的概率均为 0.5. 请通过模拟, 计算出他们平均会有多少个孩子. 并输出有多少可能性有2个孩子, 3个孩子和4个孩子. 假设概率不是 0.5, 结果会有什么不同?

数组

  1. 以下程序的运行结果是什么?
int[] a = { 1, 2, 3 };
int[] b = { 1, 2, 3 };
System.out.println(a == b);
  1. Hadamard 矩阵 H(N)2N1×2N1 的方阵. 矩阵中的元素为 0 或者 1. H(1)=[1], H(N)=[H(N1)H(N1)H(N1)¬H(N1)] 其中 ¬H(N1) 表示将H(N1)中的0变成1, 1变成0. 例如: H(2)=[1110],H(3)=[1111101011001001] 给定 N, 请输出 H(N).

  2. Alice 去参加一个聚会. Bob 也在这个聚会中. 看到 Alice 之后, Bob 把一个和 Alice 有关的八卦谣言告诉了他的一个同伴. 随后谣言开始在聚会中传播. 假设人们都按照以下方式传递谣言: 如果他第一次听到, 则从其他的人中随机选择一个 (除了告诉他的那个人和Alice), 将谣言传递出去. 如果他已经知道了这个谣言, 那么他停止传播. 请通过模拟来估计在谣言传播停止前, 所有人(除了 Alice)都知道这个谣言的概率. 同时, 请估计听到谣言人数的期望值.

  3. 给定整数 N , 输出 1 到 N 的所有排列. 利用本题测试第8题中寻找中位数的算法是否正确.

  4. 任何 1 到 N 的排列可以定义一个 {1,2,...,N} 到自身的函数 (称为一个 N 阶置换). 例如, 令排列 (2,5,4,3,1) 对应的置换为 σ, 则它的取值为 σ(1)=2, σ(2)=5, σ(3)=4, σ(4)=3, σ(5)=1. 置换 σ,τ 的积定义为它们的函数复合 τσ (即, τσ(i)=τ(σ(i)), i). 显然τσ同样为一个置换. 例如若 τ=(2,1,4,5,3),σ=(2,5,4,3,1), 则 τσ 的取值为 τσ(1)=τ(σ(1))=τ(2)=1τσ(2)=τ(σ(2))=τ(5)=3τσ(3)=τ(σ(3))=τ(4)=5τσ(4)=τ(σ(4))=τ(3)=4τσ(5)=τ(σ(5))=τ(1)=2 因此 τσ=(1,3,5,4,2). 定义衡等置换e=(1,2,..N) (即, e(i)=i, i). 定义置换 σ 的逆 σ1 满足 σσ1=σ1σ=e. 给定一个置换, 输出它的逆. 要求除了存储置换的数组外不能使用其他的数组.

  5. 8 皇后问题. 我们可以用排列代表国际象棋棋盘上皇后的位置. 例如排列 (5,2,4,1,3) 可以代表如下棋盘的布局
    * * * Q * 
    * Q * * * 
    * * * * Q 
    * * Q * * 
    Q * * * * 

其中, 每一个Q代表一个皇后, 星号表示空白棋格. 给定排列, 输出其代表的棋盘是否是一个“安全”的棋盘, 要求除了存储排列的数组外, 不能使用其他的数组. 国际象棋规则中, 一个皇后可以 “吃掉” 任何和它处于同一直线上的棋子(即同列, 同行, 同对角线, 同反对角线). 例如, 以下棋盘中A, B, C, D位置的棋子都可以被皇后吃掉, 类似的位置被称为“不安全位置”.

    * * B * * 
    * A * * * 
    * * Q * C
    * * * * * 
    D * * * * 

一个“安全”的棋盘为棋盘中所有皇后都处在安全位置 (不会被其他的皇后吃掉.)

  1. 给定N, 输出N阶蛇型矩阵S(N). 以下分别是S(1),S(2),S(3),S(4). S(1)=[1],S(2)=[1243],S(3)=[123894765],S(4)=[12341213145111615610987]

  2. 歌德巴赫猜想. 1742年, 歌德巴赫 (Goldbach) 在写给欧拉 (Euler) 的信中提出提出如下猜想: 任何大于2的偶数都能写成两个素数的和. 例如16 = 11 + 5 = 3 + 13. 这个猜想至今仍未被证实. 但对于N<4×1018的偶数, 通过计算机穷举可以确定该猜想成立. 给定N, 输出它的素数分解.

库文件

  1. 编写库文件 Statistic.java, 包含如下静态方法:

    方法 \ 说明
    double max(double a[]) 返回数组a中的最大值
    double min(double a[]) 返回数组a中的最小值
    double mean(double a[]) 返回数组a的均值
    double variance(double a[]) 返回数组a的方差
    double select(double a[], k) 返回数组a中第k大的数
    double []histogram(double a[]) 返回数组b, b[i]表示a[i]在a中出现的次数

    假定数据文件的格式为每行一个[0, 1]间的数字. 编写程序Compute.java, 从命令行获得数据文件的名称, 输出该文件中数字的最大值, 均值, 方差, 中位数. 同时输出出现次数最多的数, 最靠近均值的数, 与均值的距离小于1倍方差, 2倍方差, 3倍方差的数.