在ZIP归档文件中,保留着所有压缩文件和目录的相对路径和名称。当使用WinZIP等GUI软件打开ZIP归档文件时,可以从这些信息中重建目录的树状结构。请编写程序实现目录的树状结构的重建工作。
输入格式:
输入首先给出正整数N(≤104),表示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
结尾无空行
代码1:
# include <iostream>
# include <algorithm>
# include <string>
using namespace std;
typedef struct CSNode
{
string data; //数据域
struct CSNode* mulu{}; //指向对应长子结点的指针域
struct CSNode* file{}; //指向对应右兄弟结点的指针域
int flag{}; //判断是文件还是目录的 flag
}CSNode, * CSTree;
CSTree insertNode(CSTree t, const string& str, int flag) //核心步骤
{
CSTree a_node = new CSNode;
CSTree pre = t, ptr;
a_node->data = str; //初始化新结点
a_node->mulu = a_node->file = nullptr;
a_node->flag = flag;
if (t->mulu == nullptr) //所在目录没孩子,直接插入结点
{
t->mulu = a_node;
return t->mulu;
}
ptr = t->mulu; //由于根结点本身插入时,是插在长子位,因此另外设置 pre 当前驱结点,ptr 当 pre 的后继
while (ptr != nullptr && ((ptr->flag > a_node->flag) ||
(ptr->flag == a_node->flag && str > ptr->data)))
{
pre = ptr;
ptr = ptr->file;
}
if (ptr == nullptr) //要先判空,不然有段错误
{ //无处可插入,插在链尾
a_node->file = pre->file;
pre->file = a_node;
return a_node; //接下来以 a_node 为根目录操作
}
else if (ptr->data == a_node->data && ptr->flag == a_node->flag) //目录或文件已存在
{
delete a_node; //把申请的新结点打掉
return ptr; //接下来在已有的 ptr 目录下操作
}
else //找到了应该插入的位置
{
if (pre->data == t->data) //插在根目录的长子位
{
a_node->file = pre->mulu;
pre->mulu = a_node;
}
else //正常插入
{
a_node->file = pre->file;
pre->file = a_node;
}
return a_node; //接下来以 a_node 为根目录操作
}
}
void createTree(CSTree pre, string str)
{
int idx = 0;
getline(cin, str);
for (int i = 0; i < str.size(); i++)
{
if (str[i] == '\\') //注意用反义字符,不然会报错
{ //只要不在串尾,只会是目录
pre = insertNode(pre, str.substr(idx, i - idx), 1);
idx = i + 1; //移动字符串到下一个目录,即 '\' 之后
}
}
if (idx < str.size()) //文件只出现在字符串尾
{
insertNode(pre, str.substr(idx, str.size() - idx), 0);
}
}
void PrintTree(CSTree T, int space) //遍历函数
{
if (T == nullptr)
return;
for (int i = 0; i < space; i++) //输出空格
{
cout << " ";
}
cout << T->data << endl; //前序遍历
PrintTree(T->mulu, space + 2); //下一层多两个空格
PrintTree(T->file, space); //兄弟结点不需要多空格
}
int main()
{
int num;
string str;
CSTree Tree = new CSNode;
Tree->data = "root";
Tree->mulu = Tree->file = nullptr;
Tree->flag = 1;
cin >> num;
for (int i = 0; i <= num; i++)
createTree(Tree, str);
PrintTree(Tree, 0);
}
提交结果1:
代码2:
# include <iostream>
# include <string>
using namespace std;
typedef struct file* File;
struct file
{
string filename;
File Left;
File Right;
int ismulu; //判断是目录还是文件,ismulu=1表示是目录,ismulu=0表示是文件。目录输出的优先级比文件的高。
int blank; //记录需要输出的空格数
};
void Preorder(File F) //先序遍历输出
{
if (F == NULL)return;
int i;
for (i = 0; i < F->blank; i++)
{
cout << " ";
}
cout << F->filename << endl;
Preorder(F->Left);
Preorder(F->Right);
}
int main()
{
int N;
cin >> N;
string s;
int i, j, k;
File F = new struct file;
File q = new struct file;
File h = new struct file;
F->filename = "root"; //根结点
F->Left = F->Right = NULL;
F->blank = 0; F->ismulu = 0;
q = F;
char* name = new char[261];
int t;
for (i = 0; i < N; i++) //循环N遍,读入N行字符串
{
cin >> s;
t = 0; //记录是第几层路径下的,2*t就是需要输出的空格数
for (k = 0, j = 0; j < s.size(); j++)
{
while (j < s.size() && s[j] != '\\') //每次读入一个目录名或一个文件名
{
name[k] = s[j];
j++; k++;
}
name[k] = '\0';
k = 0;
t++; //路径层数+1
File p = new struct file; //创建结点
p->filename = name;
if (j == s.size())p->ismulu = 0;
else p->ismulu = 1;
p->Left = p->Right = NULL;
p->blank = 2 * t;
if (q->Left == NULL) //结点q没有左孩子结点,新创建的p就作为q的左孩子结点
{
q->Left = p;
}
else //结点q有左孩子结点
{
//新创建的结点p需取代原来的结点q的左孩子结点,成为结点q的左孩子结点
if (q->Left->ismulu < p->ismulu || (q->Left->ismulu == p->ismulu&&q->Left->filename > p->filename))
{
p->Right = q->Left;
q->Left = p;
}
//新创建的结点p等于结点q的左孩子结点
else if (q->Left->ismulu == p->ismulu&&q->Left->filename == p->filename)
{
p = q->Left;
}
//新创建的结点p需插入结点q的左孩子结点的右孩子序列中
else
{
q = q->Left;
while (q->Right != NULL && (q->Right->ismulu > p->ismulu || (q->Right->ismulu == p->ismulu&&q->Right->filename < p->filename))) //找到结点p插入的位置
{
q = q->Right;
}
if (q->Right&&q->Right->ismulu == p->ismulu&&q->Right->filename == p->filename) //结点p在右孩子序列中已经存在了,则不插入,更新p值为序列中存在的那个结点
{
p = q->Right;
}
else { //结点p插入结点q的左孩子结点的右孩子序列
p->Right = q->Right;
q->Right = p;
}
}
}
q = p; //更新q值。同一行输入中路径的下一层结点作为q的左孩子结点或者插入q的左孩子结点的右孩子序列中
}
q = F; //每读入一行将q初始化为根结点F
}
Preorder(F);//先序遍历
return 0;
}
提交结果2:
代码3:
# include <iostream>
# include <algorithm>
# include <cstring>
using namespace std;
typedef struct File_* File;
typedef struct File_
{
char name[270];
};
typedef struct Node* Tree;
typedef struct Node
{
char name[270]{};
Tree child[507]{};
File files[507]{};
int child_num = 0;
int files_num = 0;
};
bool cmp1(Tree a, Tree b)
{
return strcmp(a->name, b->name) < 0;
}
bool cmp2(File a, File b)
{
return strcmp(a->name, b->name) < 0;
}
void solve(char* s, Tree parent)
{
int pos = 0, len = strlen(s);
for (; (s[pos] != 92) && pos < len; ++pos);
if (s[pos] == 92)
{
char name_[270];
int exist = 0;
strncpy(name_, s, pos);
name_[pos] = '\0';
Tree now;
for (int i = 0; i < parent->child_num; ++i)
{
if (strcmp(name_, parent->child[i]->name) == 0)
{
exist = 1;
now = parent->child[i];
break;
}
}
if (!exist)
{
now = (Tree)malloc(sizeof(Node));
strcpy(now->name, name_);
now->child_num = 0;
now->files_num = 0;
parent->child[parent->child_num] = now;
parent->child_num++;
}
if (pos < (strlen(s) - 1))
{
solve(s + pos + 1, now);
}
else
return;
}
else
{
File newone = (File)malloc(sizeof(File_));
strcpy(newone->name, s);
parent->files[parent->files_num] = newone;
parent->files_num++;
return;
}
}
void PrintTree(Tree now, int depth)
{
for (int i = 0; i < depth; ++i)
cout << " ";
cout << now->name << endl;
depth++;
sort(now->child, now->child + now->child_num, cmp1);
for (int i = 0; i < now->child_num; ++i)
PrintTree(now->child[i], depth);
sort(now->files, now->files + now->files_num, cmp2);
for (int i = 0; i < now->files_num; ++i)
{
for (int i1 = 0; i1 < (depth); ++i1)
{
cout << " ";
}
cout << now->files[i]->name << endl;
}
}
int main()
{
int n;
cin >> n;
Tree root = (Tree)malloc(sizeof(Node));
strcpy(root->name, "root");
while (n--)
{
char str[270];
cin >> str;
solve(str, root);
}
PrintTree(root, 0);
return 0;
}