PTA 7-4 目录树 基础递归(基础但比较繁琐) 重写map比较器

在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

坑点

  • 输入字符串分为目录(后面有'\')文件(后面没有'\')
  • 同一文件夹下,文件夹排在文件前面
  • 文件夹和文件都要字典序

笔记一 : 重写map比较器

struct cmp { //重写string比较让文件夹排在文件前面 
	// 即 'xxx/' < 'xxx'
	bool operator() (const string& a, const string& b) const {
		if(a.back() == '\\' && b.back() != '\\') return true;
		if(a.back() != '\\' && b.back() == '\\') return false;
		return a < b;
	}
} ;

map要这样使用

map<string, Node*, cmp> chls;

文件或文件夹结构体

struct Node {
	bool dir; //标记是否是文件夹
	string name; //文件名
	map<string, Node*, cmp> chls; //子文件或子目录
	
	//以下是一些重写的比较函数
	bool operator < (const Node& no) const {
		if(name.length() > no.name.length()) return false;
		return name < no.name;
	}
	bool operator = (const Node& no) const {
		return name == no.name;
	}
	bool operator < (const string& no) const {
		if(name.length() > no.length()) return false;
		return name < no;
	}
	bool operator = (const string& nostr) const {
		return name == nostr;
	}
	
} root = { true, "root", { } };

完整代码如下

#define debug
#ifdef debug
#include 
#include "/home/majiao/mb.h"
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXN ((int)1e5+7)
#define ll long long 
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;

#ifdef debug
#define show(x...)                                 \
	do {                                           \
		cout << "\033[31;1m " << #x << " -> ";     \
		err(x);                                    \
	} while (0) 
#else
#define show(x...)  
#endif

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO {

	char print_f[105];
	void read() { }
	void print() { putchar('\n'); }

	template <typename T, typename... T2>
		inline void read(T &x, T2 &... oth) {
			x = 0;
			char ch = getchar();
			ll f = 1;
			while (!isdigit(ch)) {
				if (ch == '-') f *= -1; 
				ch = getchar();
			}
			while (isdigit(ch)) {
				x = x * 10 + ch - 48;
				ch = getchar();
			}
			x *= f;
			read(oth...);
		}
	template <typename T>
		inline void put(T x) {
			if(x==0) { putchar('0'); putchar('\n'); return; }
			if(x<0) { putchar('-'); x = -x; }
			int num=0;
			char ch[128];
			while(x) ch[++num] = x % 10 + '0', x /= 10;
			while(num) putchar(ch[num--]);
			putchar('\n');
		}
}; // namespace FastIO
using FastIO::read;
using FastIO::put;

int n, m, Q, K;
char buf[512];

struct cmp {
	bool operator() (const string& a, const string& b) const {
		if(a.back() == '\\' && b.back() != '\\') return true;
		if(a.back() != '\\' && b.back() == '\\') return false;
		return a < b;
	}
} ;

struct Node {
	bool dir; //标记是否是文件夹
	string name; //文件名
	map<string, Node*, cmp> chls; //子文件或子目录
	
	//以下是一些重写的比较函数
	bool operator < (const Node& no) const {
		if(name.length() > no.name.length()) return false;
		return name < no.name;
	}
	bool operator = (const Node& no) const {
		return name == no.name;
	}
	bool operator < (const string& no) const {
		if(name.length() > no.length()) return false;
		return name < no;
	}
	bool operator = (const string& nostr) const {
		return name == nostr;
	}
	
} root = { true, "root", { } };

void insert(Node* now, char* s, int timer) { //递归插入目录树 
	string tmp;
	//从字符串中剪裁出前面的文件夹
	//即从 'abc/def/gh' 里剪裁出 'abc/'
	for(; *s; ) {
		if((*s) == '\\') {
			s ++;
			tmp.push_back('\\');
			break;
		} else
		tmp.push_back(*s++);
	}
	if(tmp.empty()) return ;
#if 0
	for(int i=0; i<timer; i++)
		putchar(' '), putchar(' ');
	printf("%s\n", tmp.data());
#endif
	if(now->chls.count(tmp)) { //如果在当前节点里已经有子目录tmp了 就接着递归
		Node*& tnode = now->chls[tmp];
		insert(tnode, s, timer+1);
	} else { //如果当前节点没有子目录tmp就创建 并接着递归
		Node* node = new Node();
		node->name = tmp;
		now->chls[tmp] = node;
		insert(node, s, timer+1);
	}
}

void dfs(Node& now, int timer) { //dfs打印即可
	for(int i=0; i<timer; i++)
		putchar(' '), putchar(' ');
	if(now.name.back() == '\\') now.name.pop_back();
	printf("%s\n", now.name.data());
	for(auto it = now.chls.begin(); it != now.chls.end(); it ++)
		dfs(*it->second, timer+1);
}

signed main() {
#ifdef debug
	freopen("test", "r", stdin);
	// freopen("out_main", "w", stdout);
	clock_t stime = clock();
#endif
	read(n);
	for(int i=1; i<=n; i++) {
		scanf("%s ", buf);
		insert(&root, buf, 0);
	}
	auto it = root.chls.begin();
	while(it != root.chls.end()) {
//		show(it->first, it->second->name);
		it ++;
	}
	dfs(root, 0);

















#ifdef debug
	clock_t etime = clock();
	printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif 
	return 0;
}



你可能感兴趣的:(递归,目录树,重写map比较器,基础题都写的心累)