传智播客-递归(3)-文件目录列表的树状显示

顾名思义,就是写一段代码,显示指定文件的结构图,包括其所有子目录,子目录的子目录和非目录文件。

1、以缩进的形式打印出指定文件的目录结构。
这个缩进是以两个空格表示的。即文件每延后一级,打印的时候就在前面多加两个空格。采用递归方法设计的思考要点(详情请参见递归(1)),具体步骤为:
(1)在main方法里,a,给定文件(file=File(String pathName));b,列出目录并打印。
(2)上一个步骤中的b封装为一个方法(listFile(file,0)),先打印file,然后取得file的子目录和非目录文件--递归调用。
(3)打印file的表达式语句中又有一个封装的方法,indent(int tag)。只负责在要打印的目录名或文件名前加缩进,tag表示目录的级数,递归调用时,每调用一次,tag就加1。listFile(file,0)中的参数0是tag的初始值。

后来和老师的代码比较了一下,改进了以下几个地方:
[1]打印语句我一开始是放在for循环里面的,这样做的唯一缺点是打印的时候就会遗漏最上一级的目录即给定目录。(>_<其实这个问题应该很容易看出来的。。反省。。。)
[2]这句代码我本来是放在if语句的前面。其实这句放在if语句外面或里面并不影响最终运行的结果,但是放在外面的话,有种“权责不明”的感觉,或者说,代码的“任务界限”不够明晰。因为纵观这段代码,这一句只在if语句中有用到。
[3]一开始我是直接打印计算好的空格,实现效果没有区别。但是这样的代码io操作过多,运行开销大。而且以这种方式封装这个代码,体现不出程序设计的OO思想。(咳咳。。其实俺一开始就想到了是该以返回String的方式封装方法,8过偷了下懒。。)
小菜鸟学习心得:老听人说代码的优雅性,代码的高质高效啥啥的,个人以为,这些表述有些时候就体现在这些细小的地方。

下面是实现代码:
public class ListFileSimple {

 public static void main(String[] args) {
  String pathName = "G:/java/jee/itcast-workspace/java-core";
  File file = new File(pathName);
  if(!file.exists()){
   throw new IllegalArgumentException(file.getName() + " not exists!");
  }
  listFile(file, 0);
 }

 protected static void listFile(File file, int tag) {
  System.out.println(indent(tag) + file.getName()); //[1]
  //File[] files = new File[0];
  if(file.isDirectory()){
   File[] files = new File[0]; //[2]
   files = file.listFiles();
   for(int i = 0; i < files.length; i++){
    //System.out.println(indent(tag) + files[i].getName());
    listFile(files[i], tag+1);
   }
  }
 }
 
 protected static String indent(int tag){ //[3]
  StringBuilder sb = new StringBuilder();
  for(int i = 0; i < tag; i++){
   sb.append("  ");   
  }
  return sb.toString();
 }
}

2、模拟windows的tree命令显示文件方式。
如图:

目录树型结构显示

 

(1)先说明一下图中那些竖线横线的表示。张老师文档里说的是全角字符“└”、“─”、“├”和“|”组成的,我用紫光拼音的字符键盘得到了这些字符(T_T因为没能从键盘里找出来)。

 

(2)看图分析,父子节点前面的显示图例好判断,不是“└─”--最后一个子节点,就是“├─”--其他子节点。顶级节点前没有任何多余显示。主要是每个节点与其隔代祖宗节点之间的图形如何确定。单从图示上来看,主要是“|”和空格的结合,主要是这两者的显示位置需要判定。我做这个题时就是卡在这里,后来看了张老师的文档--在爷爷节点左对齐的位置上增加两个什么样的全角字符,取决于其父节点是否是爷爷节点的最小儿子,如果是,则增加两个全角的空格字符,连起来的效果为“    ”,如果不是,则增加的两个全角字符为一个“│”和一个空格字符,连起来的效果为“│  ”。如果一个节点的爷爷节点还有父节点,那么,该节点前面还要增加两个全角的空格字符,是增加“│  ”,还是“    ”,也是取决于爷爷节点是否是最小的儿子,一次递推,直到某个祖宗节点没有父节点为止。一个节点为了与所有祖宗节点对齐而在前面增加的所有字符最终就形成了一个字符串,要生成这个字符串,需要按照祖父曾祖父高祖父…的顺序一直追溯下去,并且越先追溯到的祖宗节点所对应的字符越要排在后面,这可以使用循环或递归的方式来实现。

 

(3)根据2的分析,可以得出对于对象file,需要两个辅助属性:一是判断是否父节点的最后子节点(boolean isLast),二是保存该节点的父节点(File parent)。根据OO思想,可以创建一个继承了File的包装类(FileWrapper),在此类中添加前面两个属性。这里要注意一点,FileWrapper创建对象时,应使用File对象作为构造函数的参数,如果只用String pathName的话,向上造型成File后,后面并不能直接通过File再取得FileWrapper实例,强制造型也不行(编译能通过,但是运行时会报错,因为向上造型的时候,把只属于FileWrapper的属性给丢掉了)。

 

(4)根据张老师的文档阐述,打印某个目录的自有结构图,是这个目录的自有行为,按照面向对象的设计思想,目录在这里是一个类,其自有行为应该封装在该类里面。

 

代码就不贴了。如果还有什么不理解的地方,可以向传智播客的老师请教(传智有公开的技术交流邮箱,不过回信不一定及时,毕竟老师们平时都有课,课,课余还要备课,请体谅),或者亲自来传智播客聆听:)

 

习题:
1.1 假设第1个人10岁,第2个人比第1个人大2岁,第3个人又比第2个人大2岁,…,依次递推,请用递归方式编程计算出第8个人多少岁?

 

1.2 假设n为一个大于0的正整数,按照n,2n,4n,8n,…的顺序递增,当值大于5000时,又按照..8n,4n,2n,n的顺序递减回来,请用递归方式把所有的值输出来。例如,当n=1237时,输出的结果为:1237 2474 4948 9896 9896 4948 2474 1237。
提示:写程序时,先致谢按递增方式的代码,写好递增的以后,再增加考虑递减部分。

 

1.3 求两个正整数的最大公约数的问题,两个正整数a,b,如果它们能够同时被某个数c整除,那么c就是它们的公约数,而最大公约数就是它们的所有公约数中最大的一个,当两个数的最大公约数为1时,就认为这两个数没有最大公约数,称为互质。不难知道,这个最大公约数一定是在2到a和b中较小的那个数之间的一个数。例如:9和6的最大公约数是3,15和45的最大公约数是15,7和16没有最大公约数。现在提供一种算法,先用两个数a和b相减,得出的差c的绝对值再与两个数中较小的数相减得到了差的绝对值d,再将d和之前参加减法运算的两个数中较小的一个相减……减法依次进行,直到最后减出的差为0时,参加减法运算的数(结果为0,肯定是相等的两个数)即为a和b的最大公约数,不过,当求出的最大公约数为1时,应该申明,a和b没有最大公约数。例子:求21和15的最大公约数,运算步骤为:⑴21-15=6 ⑵15-6=9 ⑶9-6=3 ⑷6-3=3 ⑸3-3=0 结论为:3。对于这个求最大公约数的算法,请读者们自己尝试着用递归的思想解决。

 

(答案代码并不长~)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值