PTA 数据结构 7-9 目录树

输入格式

输入首先给出正整数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,"  ");  // 输出
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jeffrey.pace

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值