Assignment 1 | Percolation | Princeton Algorithms

1.作业内容

渗滤系统,N*N的方格,每一个格子有p的几率是open的,1-p的几率是blocked。当p是多少的时候,这个系统几乎一定是可以渗滤(即能从第一行通到最后一行)的呢?可以通过并查集实现该系统,大量计算机实验来确定p。

实现渗滤系统,进行实验来确定p。
在这里插入图片描述

需要两个文件,Percolation.java和PercolationStas.java。

在Percolation.java中,实现渗滤系统。主要功能有:初始化一个全部封闭的渗滤系统,打开一个格子,判断格子是否打开,判断格子是否full(上图中淡蓝色已经与顶部连接的部分),得到打开格子的数量,判断系统是否已经渗滤。
在PercolationStas.java中,实现统计部分。主要功能有:从命令行参数中获取渗滤系统边长和实验次数,进行多次实验,并求出(刚好渗滤时打开格子的数量/格子总数)的平均数、标准差和置信区间。当实验次数比较大,达到几百上万时,每次运行得到的平均数几乎是一模一样的。

2. 简要分析

创建一个二维数组grid[n][n]作为网格,再创建一个WeightedQuickUnionUF作为记录连接情况。同时需要顶部和底部两个虚节点,分别连接顶部节点和底部节点。所以WeightedQuickUnionUF中数组的长度需要n*n+2个。在open一个新节点时,除了要让其对应数组的值变为true,还需要将它与其上下左右的开放节点相连。最后判断是否渗滤时,需要判断顶部和底部虚节点是否已经相连。

3. 完成过程

(1)第一次修改

在第一次提交前,我已经能够打印出正确的平均数、标准差和置信区间的值,但是第一次提交狠狠打脸,只有5/100分T T 这说明,虽然在正常运行下程序可能能够给出预期结果,但是,还有一些特殊情况没有考虑到,并且修饰符等使用不到位,而且优化代码的结构可以大量减少内存消耗,这些都是需要优化和修改的。

下面是第一次修改的内容:

  • 不变性:当实例变量的指针不再更改,可以设置为final。The private instance (or static) variable ‘uf’ can be made ‘final’; it is initialized only in the declaration or constructor. (uf指向一个对象)
  • 注释//或/*之后要加一个空格
  • 常用的常数需要设置为字段,static final

在改完这些问题后,才能正常运行其他test。

(2)第二次修改

37/100

  • isFull方法的概念理解错了。修改。
  • 抛出异常时边界没有考虑完全,例如输入边长为负。
  • 构造函数也不要忘记抛出异常,输入参数可能不合理。
  • 没有考虑到边长为1的情况。如果边长为1,则一开始就和首尾联通,满足渗滤。所以要单独考虑这个情况。
  • 之前把重复做实验的过程写在了main函数里,其实可以直接写在PercolationStas的构造函数里,在main函数只要读取边长n和实验次数trails,并初始化PercolationStas对象即可得到实验结果,对使用者来说更方便,并且能够节省许多内存,这一点的原因与下面两点有关。
  • PercolationStas内存超出限制。一开始我在写这个类的时候,使用一个实例变量res[trails]来存储每次试验结果,再在mean()方法中使用StdStats.mean(res)方法计算平均数,置信区间和标准差同理。但是这样会浪费巨大的空间!可以将res[trails]作为本地变量,在构造函数中初始化,在构造函数中完成平均值等的计算,只需要将平均值等作为实例变量保存起来即可,调用完构造函数,res[trails]就可以被回收了。
    如果使用res[trails]作为实例变量,那么只要初始化PercolationStas,系统就会分配一个这么长的数组,并且一直保存,非常浪费。
  • 同上,也没有必要将Percolation对象作为实例变量,只需要在构造函数中使用即可。

(3)第三次修改

59/100

  • 平均值等实例变量只会被赋一次值,所以可以声明为final。
  • 忘记考虑isFull必须同时也是isOpen了。

最终:94/100(80分算过)
github

  • 待解决的问题:backwash(理解为反洗)
    这个问题比较复杂,一时也没有想好,作业要求里也不强求。主要还是isFull的问题。一旦系统渗滤,和底部联通的也就会被认为是isFull了。(因为我的isFull写法是判断格子和顶部是否联通,如果渗滤了顶部和底部也就联通了)
    在这里插入图片描述

4. 补充知识:printf

  • 制表符\t
    制表符\t输出的时候,会移动输出光标,实现对齐效果。因此可以在输出的对应位置,增加\t来实现对齐。但有个缺点:要求每行相同列输出占用空间差别不可以太大。(若输出的是数字信息,可以直接将log信息copy到excel表格中,能很好地统计数字数值信息)

  • 加入占用宽度控制数字
    使用printf格式化输出时,每个控制字符可以写成%nC的形式,如%10d, %12f, %5c, %20s等等,其对应的是不足部分左侧补空格,实现右对齐效果;若要不足部分右侧补空格,只需要在宽度字符前加-符号即可,如%-12f,此时实现的是左对齐效果。

  • 在“”中输入特殊字符需要转义字符。例如,打印%需要写%%。还能够:
    System.out.printf("%-10s","abc"); //输出10列,左对齐(-号表示左对齐)
    System.out.printf("%8d",23); //输出8列, 右对齐

  • 表4-4 格式化转换符
    格式化转换符定义
    %b 无符号二进制整数
    %c 字符
    %d、i 十进制整数
    %e 科学计数法浮点数
    %E 使用大写字母E 的科学计数法浮点数
    %f、%F 浮点数
    %g 使用e 或f 转换符的浮点数,取其最小宽度
    %G 使用e 或f 转换符的浮点数,取其最大宽度
    %id、%D 长整型十进制数
    %lu、%U 无符号长整型十进制数
    %lo、%O 长整型八进制数
    %p 指针(十六进制数)
    %s 字符串
    %u 无符号的十进制数
    %x 十六进制数
    %X 使用大写字母X 的十六进制数
    %lx 长整型十六进制数
    %% 打印百分号实量

  • 表4-5  标记修饰符
    转换符定 义
    %- 左对齐修饰符
    %# 如果是八进制数,则在显示时带上前导0;如果是十六进制数,则在显示时带有前缀0x
    %+ 对于使用d、e、f 和g 的转换符,显示其整数部分,并显示正负号+、-
    %0 把显示内容中的空白部分以0 补足
    %number 最大字段宽度。譬如,若number 为6(如%6d),说明最大字段宽度是6
    %.number 指定浮点数的精度。例如,%.2f 表示小数点后两位 ;%8.2 表示最大字段宽度为8,并
    精确到小数点后两位

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值