输入格式
输入首先给出正整数N(≤104),表示ZIP归档文件中的文件和目录的数量。随后N行,每行有如下格式的文件或目录的相对路径和名称(每行不超过260个字符):
- 路径和名称中的字符仅包括英文字母(区分大小写);
- 符号“\”仅作为路径分隔符出现;
- 目录以符号“\”结束;
- 不存在重复的输入项目;
- 整个输入大小不超过2MB。
输出格式
假设所有的路径都相对于root目录。从root目录开始,在输出时每个目录首先输出自己的名字,然后以字典序输出所有子目录,然后以字典序输出所有文件。注意,在输出时,应根据目录的相对关系使用空格进行缩进,每级目录或文件比上一级多缩进2个空格。
测试样例和测试点
------------------------------------
2
a\aa\b
aa\c
root
a
aa
b
aa
c
------------------------------------
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
------------------------------------
3
b\bb\bbb
bbb\bb\b
bbb\a
root
b
bb
bbb
bbb
bb
b
a
------------------------------------
2
a\aa\aaa
a\aa\bbb\
root
a
aa
bbb
aaa
------------------------------------
1
z\
root
z
------------------------------------
思路
for(在父节点的子目录集中,寻找有没有同名的目录)
{
if(存在)
{
更新父节点pre为查找到的同名的目录节点
break;
}
}
if(不存在)
{
新建节点node,写入数据
if(若为文件)
{
将node 放入父节点pre的子文件集vector
将node的名称 放入父节点pre的子文件名称集set
}
else if(若为目录)
{
将node 放入父节点pre的子目录集vector
将node的名称 放入父节点pre的子目录名称集set
更新父节点pre
}
}
每处理完一行数据,将父节点pre置为根目录Root
代码
#include <iostream>
#include <string>
#include <vector>
#include <set>
using namespace std;
typedef struct Tree{
string name; // 目录或文件的名字
vector<struct Tree*> cataPtrVec; // 指向子目录的指针集
vector<struct Tree*> filePtrVec; // 指向子文件的指针集
set<string> CataNameSet; // 存放子目录的名称,用于字典序排序
set<string> FileNameSet; // 存放子文件的名称,用于字典序排序
}*ptrOfCatalogue,Catalogue;
ptrOfCatalogue pre, Root; // 分别为指向父节点的指针、指向根目录Root的指针
void BuildTree(string& str) // 建树
{
bool exisit = false;
for (auto it = pre->cataPtrVec.begin(); it != pre->cataPtrVec.end(); it++) // 在父节点的子目录集中查找该名称。(查不到文件)
{
if ((*it)->name == str) // 若pre的子目录集中有名为str的目录,不用创建新节点
{
exisit = true;
pre = *it; // 更新pre
break;
}
}
if (!exisit) // 在pre目录下新建节点。条件:1、pre的子目录集中没有名为str的目录;2、str是文件名
{
ptrOfCatalogue node = new Catalogue; // 创建节点
node->name = str;
if (str[str.size() - 1] != 92) // 若为文件,并插入到文件set。(注:92是'\'的ASCII码)
{
pre->filePtrVec.push_back(node); // 将该节点保存到父节点的子文件集vector
pre->FileNameSet.insert(node->name);
}
else // 若为目录,并插入到目录set,更新pre
{
pre->cataPtrVec.push_back(node); // 将该节点保存到父节点的子目录集vector
pre->CataNameSet.insert(node->name);
pre = node;
}
}
}
void inputData(string &str, int nowIndex) // 对于单行字符串的输入处理
{
int strLength = str.size();
for (int i = nowIndex; i < str.size(); i++) // 对于单行字符串处理
{
if (str[i] == '\\' || i == str.size() - 1) // 若 此时下标为i的字符是'\' 或 遍历到了最后一个字符
{
string x = str.substr(nowIndex, i - nowIndex + 1); // 截取
BuildTree(x);
nowIndex = i + 1; // 更新下一段的起始下标
}
}
}
void initRoot() // 初始化根目录
{
Root = new Catalogue; // 创建根目录的节点
Root->name = "root";
pre = Root; // 初始上一级目录为根目录
}
void printByDFS(ptrOfCatalogue node,string blank) // 递归输出
{
for (auto p = node->CataNameSet.begin(); p != node->CataNameSet.end(); p++)
{
string ans = (*p).substr(0,(*p).size()-1); // 略去目录的最后一个字符(即'\')并输出
cout << endl << blank << ans;
auto it = node->cataPtrVec.begin();
for(; it != node->cataPtrVec.end(); it++) // 根据字典序,在cataPtrVec中获取下一个节点的指针
if ((*it)->name == *p)
break;
printByDFS(*it, blank+" ");
}
for (auto p = node->FileNameSet.begin(); p != node->FileNameSet.end(); p++)
{
cout << endl << blank << *p;
auto it = node->filePtrVec.begin();
for (; it != node->filePtrVec.end(); it++) // 根据字典序,在filePtrVec中获取下一个节点的指针
if ((*it)->name == *p)
break;
printByDFS(*it, blank+" ");
}
return;
}
int main()
{
int sumOfLine;
cin >> sumOfLine; // 输入总行数
initRoot();
for (int i = 0; i < sumOfLine; i++)
{
string str;
cin >> str;
inputData(str, 0); // 处理输入的单行字符串的函数(起始下标初始化为0)
pre = Root; // 每行输入结束后,将pre置为Root
}
cout << "root";
printByDFS(Root," "); // 输出
}