在ZIP归档文件中,保留着所有压缩文件和目录的相对路径和名称。当使用WinZIP等GUI软件打开ZIP归档文件时,可以从这些信息中重建目录的树状结构。请编写程序实现目录的树状结构的重建工作。
输入格式:
输入首先给出正整数N(≤10
4
),表示ZIP归档文件中的文件和目录的数量。随后N行,每行有如下格式的文件或目录的相对路径和名称(每行不超过260个字符):
路径和名称中的字符仅包括英文字母(区分大小写);
符号“\”仅作为路径分隔符出现;
目录以符号“\”结束;
不存在重复的输入项目;
整个输入大小不超过2MB。
输出格式:
假设所有的路径都相对于root目录。从root目录开始,在输出时每个目录首先输出自己的名字,然后以字典序输出所有子目录,然后以字典序输出所有文件。注意,在输出时,应根据目录的相对关系使用空格进行缩进,每级目录或文件比上一级多缩进2个空格。
输入样例:
7
b
c
ab\cd
a\bc
ab\d
a\d\a
a\d\z
输出样例:
root
a
d
z
a
bc
ab
cd
d
c
b
看了大佬的代码:5-30 目录树 (30分)
自己写了点理解,自己刚开始下笔时最难的就是,在建立子与根的同时,还要判断字典顺序,建立了子与根的关系了,再排序。。。这样又会打乱整个布局,,,还有还要判断,打乱后的原目录位置进行插入,感觉特别复杂,,,心里实在没有逻辑的层次感。。。也怪自己心里总想着图和二叉树(比如3个分叉,4个分叉的树。。。。甚至不同数目分叉的树),心里总是想不出一个完美的模型来解决,,,然后,看了大佬的,才发现,其实无论几个分叉,,都是只有2个关系:
1:和自己同级的关系
1-1:和自己同类型
1-2:和自己不同类型
2:和自己不同级的关系
2-1:比自己大一级的关系:这个在其实也不算,对于比自己大一级的,自己其实就是大一级的子一级
2-2:比自己小一级的关系
总结就是:大佬这个结构完美的说明了所有关系,所以,,,建立模型好难!!!!
换句话就是,只有理清题目的逻辑层次,能划分且描述题目的里里外外,才能解决题目。
struct node {
char*Name;
//先判断是不是目录,是目录才有File和Catalog,否则只可能有Brother
Bool isCatalog;
//指示本目录的子目录
Node File;
//指示本目录的子文件
Node Catalog;
//指示和本目录或文件平行的目录或文件
Node Brother;
}
代码
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#define True 1
#define False 0
typedef int Bool;
typedef struct node* Node;
struct node {
char*Name;
//先判断是不是目录,是目录才有File和Catalog,否则只可能有Brother
Bool isCatalog;
//指示本目录的子目录
Node File;
//指示本目录的子文件
Node Catalog;
//指示和本目录或文件平行的目录或文件
Node Brother;
} Head;
void Print(Node, int);
void Read();
Node New(char*);
Node InsertCatalog(Node, char*);
Node InsertFile(Node, char*);
int main() {
int n;
scanf("%d", &n);
Head.Name = (char*) malloc(sizeof(char) * 5);
strcpy(Head.Name, "root");
Head.File = NULL;
Head.Catalog = NULL;
Head.Brother = NULL;
Head.isCatalog = True;
for (int i = 0; i < n; i++) {
getchar();
Read();
}
Print(&Head, 0);
return 0;
}
void Read() {
char FileName[261];
Node HTemp = &Head;
scanf("%s", FileName);
char words[261];
//L记录的是目录(或文件名)名的第一个字符的起点位置
int j, L = 0;
for (int i = 0; i < strlen(FileName); i++) {
//第一个'\'字符前的名字
if (FileName[i] == '\\') {
for (j = L; j < i; j++) {
//获取名
words[j - L] = FileName[j];
}
words[j - L] = '\0';
//插入目录(有'\'的前面一定是目录名,没有就不是目录名,而是文件名)
HTemp->Catalog = InsertCatalog(HTemp->Catalog, words);
//一个'\'就是一个目录的结束,执行完以后还要再继续读取下一个目录,而下一个目录是建立在上一个目录
//所以这里要进行跳跃
HTemp = HTemp->Catalog;
//上面我们知道,此刻我们到达了下一个要插入的目录(或文件)的上一级目录
//但是,我们这个时候到达的是字典顺序排好的第一个目录,,,不一定是上面我们刚刚插入的目录
//所以这里要加个循环来寻找到达的插入的目录
while (strcmp(HTemp->Name, words))
HTemp = HTemp->Brother;
L = i + 1;
}
}
//显然,如果L==strlen(FileName)那么目录结构输入时应该是:XXX\XXX\XXX\ 最后一个一定是'\'字符,最后插入的是目录名
//但如果L<strlen(FileName)那么目录结构输入时应该是:XXX\XXX\xxx 最后一个不是'\'字符,最后插入的是文件名
if (L < strlen(FileName)) {
for (j = L; j <= strlen(FileName); j++) {
words[j - L] = FileName[j];
}
HTemp->File = InsertFile(HTemp->File, words);
}
}
Node InsertCatalog(Node Catalog, char*InsertCatalogName) {
//如果文件目录不存在或者字典要插入的目录名字典顺序比当前第一个小
//那就应该插在第一个位置
if (!Catalog || strcmp(Catalog->Name, InsertCatalogName) > 0) {
Node temp = New(InsertCatalogName);
temp->Brother = Catalog;
return temp;
}
//如果目录已经存在直接返回
if (strcmp(Catalog->Name, InsertCatalogName) == 0)
return Catalog;
//如果不满足上面的条件,则进入与H目录同层的目录进行判断
//显然,H的同层下(H层以上的目录不在范围内容)目录结构发生改变,则全局就将发视变化
Catalog->Brother = InsertCatalog(Catalog->Brother, InsertCatalogName);
return Catalog;
}
Node InsertFile(Node File, char*InsertFileName) {
//同上InsertCatalog
if (!File || strcmp(File->Name, InsertFileName) > 0) {
Node Insert = New(InsertFileName);
Insert->isCatalog = False;
Insert->Brother = File;
return Insert;
}
//这里我其实觉得也应该添加一个判断,毕竟也有可能出现重复文件名
// if (strcmp(File->Name, InsertFileName) == 0)
// return File;
//但仔细一思考,该题是目录清单,清单所确定的目录下不可能出现同一文件,,,至于为啥可能出现同一文件夹名字呢?
//这是因为目录清单每个条例只能确定一个文件路径或者文件夹路径,但同一文件夹下可能有多个文件或者多个目录,所以可能出现同一文件夹名字
File->Brother = InsertFile(File->Brother, InsertFileName);
return File;
}
Node New(char*Name) {
Node newNode = (Node) malloc(sizeof(struct node));
newNode->Name = (char*) malloc(sizeof(char) * (strlen(Name) + 1));
strcpy(newNode->Name, Name);
newNode->Brother = NULL;
newNode->File = NULL;
newNode->Catalog = NULL;
//默认是在建目录
newNode->isCatalog = True;
return newNode;
}
void Print(Node H, int Space) {
if (H) {
for (int i = 0; i < Space; i++)
printf(" ");
//打印顺序
//1-1 根目录名
// 1-2 子目录名
// 1-3 文件名
//1-4 异根目录名
//1-1
printf("%s\n", H->Name);
//1-2
if (H->isCatalog == 1)
Print(H->Catalog, Space + 2);
//1-3
Print(H->File, Space + 2);
//1-4
Print(H->Brother, Space);
}
}
再次感谢大佬:5-30 目录树 (30分)