问题描述
要求在给出Unix或windows下目录和文件信息的前提下,编程实现将其排列成一棵具有一定缩进的树。基本要求
在给定的磁盘目录下,参照下表分层缩进输出文件目录结构
|_*/usr
|_*mark
| |_hw.c
| |_*course
|_aa.txt
|_*alex
|_hw.c
本课程设计,我写了2个文件,一个是Main.java,一个是TreeNode.java。当然,用Java是因为File,等等类相当好用,方便快捷。输出子目录树,我用了孩子链式存储方式,先形成一棵树,然后再层次遍历它,看了一下其他大神写的多叉树的类,自己理解了一下相应的点,并且在适当的地方用到了。。
由于题目难度比较水,我又多增添了两个功能(水的点),下面贴出来,供大家参考。有不对的地方欢迎大家批评指正。
这不是重写方法后的代码,因为这是数据结构的课设,后面重写了栈和队列,,仅供参考。谢谢~
下面是Main.java
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
/**
* @author 计161 CJY in School of Computer and Control Engineering in YTU,
* 数据结构课程设计 Made on 2017-12-15 14:45:38,
* Project's name: Directory's Tree
*/
public class Main {
static Scanner in = new Scanner(System.in);
public static final int MAX_Node_Num = 0x3f3f3f;
public static int filecount = 0;
public static int directorycount = 0;
public static int Cnt = 0;
public static int depth = 0;
public static int flag = 1;
public static String ex = "|_";
public static Stack<String> stack = new Stack<String>();
public static Queue<String> queue = new LinkedList<String>();
public static String x = "*";
static TreeNode[] tn = new TreeNode[MAX_Node_Num];
public static int TreeNodeNum_Start = 1;
public static int tmp = 0;
public static int cnt = 0; // 计数要输出缩进个数
/**
* @param x 文件夹前缀
* @param Cnt 记录当前节点的子节点个数
* @param Max_Node_Num 最大树节点个数
* @param filecount 记录文件个数
* @param directorycount 记录文件夹个数
* @param depth 初始化深度
* @param stack 用栈记录当前文件夹内的的文件等
* @param ex 树形表示前缀
* @param tmp 临时表示TreeNodeNum
* @param currentDepth 表示当前文件树深度
* @param TreeNodeNum_Start 表示起始Node节点
* @param queue 用队列记录兄弟目录
*
*/
/**
*
* 首先输入一个路径(看做一个节点),然后判断是否存在该路径,
* 如果存在的话,选择要调用的方法,当选择4的时候,将flag置0,结束程序
*/
public static void main(String[] args) throws java.lang.NullPointerException, IOException {
// TODO Auto-generated method stub
tn[0] = new TreeNode();
System.out.println("please enter a Path Name:");
String root = new String(in.nextLine());
File path = new File(root);
if (path.exists()) {
while (true) {
if (flag == 0)
break;
goto_methods(choice(), path);
}
} else
System.out.println("This path doesn't exist!");
in.close();
System.out.println("程序结束,欢迎使用");
}
/**
* @param choice 为choice方法返回的整型值
* @param path 输入的访问路径
* @throws IOException
*
* 通过调用choice方法返回选项值,确定调用的方法
*/
public static void goto_methods(int choice, File path) throws IOException {
// TODO Auto-generated method stub
switch (choice) {
case 1:
print_subTree(path);
break;
case 2:
print_parentTree(path);
break;
case 3:
print_brotherTree(path);
break;
default:
flag = 0;
break;
}
}
/**
* @return 返回的整型值作为goto_methods方法的参数
*/
private static int choice() {
// TODO Auto-generated method stub
String n ;
int s ;
while (true) {
System.out.println("-----------------美丽的分割线------------------");
System.out.println("|Make a Choice : |");
System.out.println("|1.Print its directory's subtrees. |");
System.out.println("|2.Print its parent directory tree. |");
System.out.println("|3.Print its brother tree set. |");
System.out.println("|4.Exit. |");
System.out.println("-----------------美丽的分割线------------------");
n = in.next();
s = n.charAt(0)-'0';
if(s >= 1 && s <=4)
break;
else
System.out.println("Your Choice is illegal, plz Enter again.");
}
return s;
}
/**
* @param path 手动输入的路径
* @throws IOException
*
* 输出子目录树(Tree)
*
* 该方法通过先判断是否存在以及是否是一个目录,随后调用build_Tree方法,建立一颗文件的多叉搜索树
*/
public static void print_subTree(File path) throws IOException {
// TODO Auto-generated method stub
if (path.exists()) {
if (path.isDirectory()) {
build_Tree(path, depth);
} else if (path.isFile()) {
System.out.println(x + ex + path.getName());
filecount++;
} else
System.out.println("Error!");
} else
System.out.println("This Path doesn't exist!");
System.out.println(x + path.getName());
for (int i = 0; i < filecount + directorycount; i++) {
tn[i].traverse();
if (depth < tn[i].getDepth())
depth = tn[i].getDepth();
}
depth++;
System.out.println("该目录下一共有:" + filecount + "个文件," + directorycount + "个目录, 目录深度为:" + depth);
}
/**
* @param path 手动输入的路径
*
* 输出当前路径的父路径(Stack & Tree)
*
* 通过获取路径的父路径,将父路径存入栈中,再以此为路径,求得父路径 存入栈,直至其父路径为null,随后生成一颗树(也可以不这么做),
* 出栈栈顶元素,作为树的根节点,然后继续出栈,将其后面的元素作为根节点的子节点。
*/
private static void print_parentTree(File path) {
// TODO Auto-generated method stub
int cnt = 0;
int tmp = 0;
File prepath = path;
tn[0] = new TreeNode();
tn[0].setNodeName(path.getName());
while (path.getParent() != null){
stack.push(path.getParent());
if(path.getParent() != null)
path = new File(path.getParent());
}
// 判断是否栈空,并将栈中元素纳入树,出栈
while (!stack.isEmpty()) {
tmp = cnt;
tn[++cnt] = new TreeNode();
tn[cnt].setNodeName(x + stack.peek());
tn[cnt].setDepth(tmp);
tn[tmp].addChildNode(tn[cnt]);
stack.pop();
}
// 层次遍历各个节点
for (int i = 0; i < cnt; i++)
tn[i].traverse();
for(int i = 0 ; i < cnt ; i++)
System.out.print(" ");
if(prepath.isDirectory())
System.out.println(ex + x +prepath.getPath());
else
System.out.println(ex + prepath.getPath());
System.out.println("该目录的父目录共有:" + cnt +"个" );
}
/**
* @param path 手动输入的路径
*
* 输出该节点的兄弟节点(Queue)
*
* 先获取当前路径的父节点,然后通过父节点获取其所有的子节点,并加入队列,获取完当前所有子节点之后,出队所有元素并输出结果。
*/
private static void print_brotherTree(File path) {
// TODO Auto-generated method stub
if (path.getParent() != null) {
File newpath = new File(path.getParent());
String[] str = newpath.list();
for (int i = 0; i < str.length; i++) {
File thispath = new File(str[i]);
if(thispath.getName().equals(path.getName()))
continue;
if (thispath.isDirectory()) {
queue.offer(x + thispath.getName());
} else {
queue.offer(thispath.getName());
}
}
System.out.println("This Path's Brother Tree:");
// 当队不为空时,输出队首元素
while (queue.peek() != null) {
if (queue.peek() != path.getName()){
File tmpFile = new File(queue.peek());
if(tmpFile.isDirectory())
System.out.println(ex + x + queue.peek());
else
System.out.println(ex + queue.peek());
}
queue.poll();
}
} else
System.out.println("This path doesn't have Brother Tree!");
}
/**
* @param path 手动输入的路径
* @param depth 构建树的深度(层数)
* @throws IOException
*
* 构建一颗多叉树(Tree)
*
* 首先将输入的path路径作为树的根节点,获取path路径下的所有文件列表,将其路径下的文件和文件夹作为该根节点的子节点,
* 记录该节点的节点下标,该节点的父节点下标,以及该节点的深度(层数),
* 如果子节点为目录,则将该节点作为临时的根节点,同时从该节点进行遍历,获取该节点下的文件列表,将其作为目录的子节点,
* 同时,记录作为目录的子节点的个数。
* 直到所有的节点遍历完毕,当前建立好了一颗多叉搜索树。
* 遍历时,通过遍历每个节点,看是否有子节点列表,有的话则将其输出,并继续查找是否有子节点
* 遍历时,通过访问度不为0的节点来遍历文件目录,不遍历叶子结点。
*/
public static void build_Tree(File path, int depth) throws IOException {
// TODO Auto-generated method stub
String[] arr = path.list();
int currentDepth = depth + 1;
if (depth == 0) {
tn[0].setNodeName(x + path.getName());
tn[0].setDepth(tmp);
} else {
tn[TreeNodeNum_Start] = new TreeNode();
tn[TreeNodeNum_Start].setNodeName(x + path.getName());
tn[TreeNodeNum_Start].setDepth(depth);
tn[TreeNodeNum_Start].setSelfId(TreeNodeNum_Start);
tn[TreeNodeNum_Start].setParentId(tmp);
tn[tmp].addChildNode(tn[TreeNodeNum_Start]);
tn[tmp].setCnt(Cnt++);
tmp = TreeNodeNum_Start;
Cnt = 0;
TreeNodeNum_Start++;
}
for (int i = 0; i < arr.length; i++) {
String str = arr[i];
File file = new File(path.getPath(), str);
if (file.isDirectory()) {
directorycount++;
build_Tree(file.getCanonicalFile(), currentDepth);// 递归调用
} else {
tn[TreeNodeNum_Start] = new TreeNode();
tn[TreeNodeNum_Start].setNodeName(file.getName());
tn[TreeNodeNum_Start].setDepth(currentDepth);
tn[TreeNodeNum_Start].setSelfId(TreeNodeNum_Start);
tn[TreeNodeNum_Start].setParentId(tmp);
tn[tmp].addChildNode(tn[TreeNodeNum_Start]);
tn[tmp].setCnt(Cnt++);
TreeNodeNum_Start++;
filecount++;
}
}
}
}
下面是TreeNode.Java
这个类是构建多叉树的,看了一下这个博客。然后加了点功能,保留了他的功能,感谢这位大佬,这是他的博文地址http://ylq365.iteye.com/blog/980627
import java.util.List;
import java.util.ArrayList;
import java.io.Serializable;
/**
* @author 计161 CJY in School of Computer and Control Engineering in YTU,
* 数据结构课程设计 Made on 2017-12-15 14:50:21,
* Project's name: Directory's Tree
*
*/
public class TreeNode implements Serializable {
private int parentId;
private int selfId;
private int depth = 0;
private String space = " ";
private String ex = "_";
private String ex1 = "|";
private int cnt = 0;
protected String nodeName;
protected TreeNode parentNode;
protected List<TreeNode> childList;
public TreeNode() {
initChildList();
}
public TreeNode(TreeNode parentNode) {
this.getParentNode();
initChildList();
}
public boolean isLeaf() {
if (childList == null) {
return true;
} else {
if (childList.isEmpty()) {
return true;
} else {
return false;
}
}
}
/* 插入一个child节点到当前节点中 */
public void addChildNode(TreeNode treeNode) {
initChildList();
childList.add(treeNode);
}
public void initChildList() {
if (childList == null)
childList = new ArrayList<TreeNode>();
}
/* 返回当前节点的父辈节点集合 */
public List<TreeNode> getElders() {
List<TreeNode> elderList = new ArrayList<TreeNode>();
TreeNode parentNode = this.getParentNode();
if (parentNode == null) {
return elderList;
} else {
elderList.add(parentNode);
elderList.addAll(parentNode.getElders());
return elderList;
}
}
/* 返回当前节点的晚辈集合 */
public List<TreeNode> getJuniors() {
List<TreeNode> juniorList = new ArrayList<TreeNode>();
List<TreeNode> childList = this.getChildList();
if (childList == null) {
return juniorList;
} else {
int childNumber = childList.size();
for (int i = 0; i < childNumber; i++) {
TreeNode junior = childList.get(i);
juniorList.add(junior);
juniorList.addAll(junior.getJuniors());
}
return juniorList;
}
}
/* 返回当前节点的孩子集合 */
public List<TreeNode> getChildList() {
return childList;
}
/* 删除节点和它下面的晚辈 */
public void deleteNode() {
TreeNode parentNode = this.getParentNode();
int id = this.getSelfId();
if (parentNode != null) {
parentNode.deleteChildNode(id);
}
}
/* 删除当前节点的某个子节点 */
public void deleteChildNode(int childId) {
List<TreeNode> childList = this.getChildList();
int childNumber = childList.size();
for (int i = 0; i < childNumber; i++) {
TreeNode child = childList.get(i);
if (child.getSelfId() == childId) {
childList.remove(i);
return;
}
}
}
/* 动态的插入一个新的节点到当前树中 */
public boolean insertJuniorNode(TreeNode treeNode) {
int juniorParentId = treeNode.getParentId();
if (this.parentId == juniorParentId) {
addChildNode(treeNode);
return true;
} else {
List<TreeNode> childList = this.getChildList();
int childNumber = childList.size();
boolean insertFlag;
for (int i = 0; i < childNumber; i++) {
TreeNode childNode = childList.get(i);
insertFlag = childNode.insertJuniorNode(treeNode);
if (insertFlag == true)
return true;
}
return false;
}
}
/* 找到一颗树中某个节点 */
public TreeNode findTreeNodeById(int id) {
if (this.selfId == id)
return this;
if (childList.isEmpty() || childList == null) {
return null;
} else {
int childNumber = childList.size();
for (int i = 0; i < childNumber; i++) {
TreeNode child = childList.get(i);
TreeNode resultNode = child.findTreeNodeById(id);
if (resultNode != null) {
return resultNode;
}
}
return null;
}
}
/* 遍历一棵树,层次遍历,以及输出节点数*/
public void traverse() {
if (selfId < 0)
return;
if (childList == null || childList.isEmpty())
return;
int childNumber = childList.size();
for (int i = 0; i < childNumber; i++) {
TreeNode child = childList.get(i);
for(int j = 0 ;j < child.depth; j++)
System.out.print(space+ex1);
System.out.println(ex+child.getNodeName());
}
}
public int getParentId() {
return parentId;
}
public void setDepth(int depth){
this.depth = depth;
}
public int getDepth(){
return depth;
}
public void setParentId(int parentId) {
this.parentId = parentId;
}
public int getSelfId() {
return selfId;
}
public void setSelfId(int selfId) {
this.selfId = selfId;
}
public TreeNode getParentNode() {
return parentNode;
}
public void setParentNode(TreeNode parentNode) {
this.parentNode = parentNode;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public void setCnt(int cnt){
this.cnt = cnt;
}
public int getCnt(){
return cnt;
}
}
好了就是这些,具体的步骤我写在注释里了,欢迎提意见~我也是菜鸡一枚。
最后再次感谢大佬的博文,谢谢!