习题1.1.32
直方图。假设标准输入流中含有一系列 double 值。编写一段程序,从命令行接受一个整数N和两个doubl值l和r。将 (l,r) 分为 N 段并使用 StdDraw 画出输入流中的值落入每段的数量的直方图。
要点分析
一.
直方图首先看到该题的同学可能都会一脸懵逼,什么是直方图呀?这里简单介绍一下直方图的概念:直方图示例在统计学中,直方图(英语:Histogram)是一种对数据分布情况的图形表示,是一种二维统计图表,它的两个坐标分别是统计样本和该样本对应的某个属性的度量。[1] 一般用横轴表示数据类型,纵轴表示分布情况。直方图的主要作用有:
- 显示质量波直方图与标准的对照直方图与标准的对照动的状态;
- 较直观地传递有关过程质量状况的信息;
- 通过研究质量波动状况之后,就能掌握过程的状况,从而确定在什么地方集中力量进行质量改进工作。[2]
二.
画直方图可以用到StdDraw标准绘图库中的filledRectangle 方法。关于此方法的介绍在课本第27页。
这里给出该方法的API:
public class StdDraw{ static void filledRectangle(double x, double y, duoble rw, double rh) }
其中,该方法的参数解释如下:
rw:矩形的宽度
rh : 矩形的高度
x,y:这里的x和y我们可以这样理解:
把整个画布看做一个1 * 1 正方形,x 和y 的值均在0和1之间,举个例子:
如果x = 0, y = 0,则该矩形的处于画布的左下角
如果x =0.5, y = 0.5,则该矩形处于画布的正中间
public class Test { public static void main(String[] args) { double x = 0 ; double y = 0; double rw = 0.02; double rh = 0.08 ; StdDraw.filledRectangle(x,y,rw,rh); double x1 = 0.5; double y1 = 0.5; double rw1 = 0.02; double rh1 = 0.08 ; StdDraw.filledRectangle(x1,y1,rw1,rh1); } }
输出如下图:
通过上面的例子我们也可以看出,其实该方法并不是一次画出整个直方图,而是利用循环或者其他方法,通过输出多个矩形,来组成一个直方图,比如课本第45页中间的例子:
import edu.princeton.cs.algs4.StdDraw; import edu.princeton.cs.algs4.StdRandom; public class Test { public static void main(String[] args) { int N = 50; double [] a = new double[N]; for (int i = 0; i < N; i++) { a[i] = StdRandom.random(); } for (int i = 0; i < N; i++) { double x = 1.0 * i / N; double y = a[i] / 2.0; double rw = 0.5 / N; double rh = a[i] / 2.0 ; StdDraw.filledRectangle(x,y,rw,rh); } } }
输出如下:
三.
本题中,rw我们可以随便定义,因为每个矩形的宽度,与本题的数据无关
rh就是输入流中的值落入每段的数量
首先通过(r – l)/N 算出每段的长度,然后遍历整个数组,计算每个数组的值落入每段的数量,将其作为rh的值即可
参考答案
import edu.princeton.cs.algs4.StdDraw; import java.util.Scanner; public class TEST_1_1_33 { public static void main(String[] args) { double [] d = new double[10]; //存放标准输入流中输入的double值 int N = Integer.parseInt(args[0]); //从命令行接受整数N int h[] = new int[N];//存放d数组中每个值落入每段的数量 double l = Double.parseDouble(args[1]);//从命令行接受double l double r = Double.parseDouble(args[2]);//从命令行接受double r Scanner input = new Scanner(System.in); System.out.println("请输入几个double值:\n"); for (int i = 0; i < N; i++) { d[i] = input.nextDouble(); } data(d,l,r,N,h); histogramh(N,d,h); } public static void data(double[]d, double l, double r,int N,int h[]) { double i[] = new double[N]; double av = (r - l) / N; i[0] = av; for (int j = 1; j < N; j++) { i[j] = i[j - 1] + av; //算出每个分段点的值 } for (int j = 0; j < d.length; j++) { for (int k = 0; k < N; k++) { if (d[j] < i[k]) { h[k]++; //算出数组中每个值落入每段的数量 break; } } } } public static void histogramh(int N,double[] d,int h[]) { for (int i = 0; i < N; i++) { double x = (1.0 * i ) / N; double y = h[i] / 5.0; double rw = 0.5 / N; StdDraw.filledRectangle(x,y,rw,h[i]/5.0); } } }
输入:1 3 5 7 9 11 13 15 15 17 几个数,输出如下图:
参考资料
[1] 维基百科
[2] 百度百科
请登录之后再进行评论