显然本题是要将文件组织成一棵树,直观的想法就是用相应的文件名(字符串)作为结点的data域,同时给结点编号,形成一个一一映射。
如果用指针和动态建树的方法,由于我们并不确定一个文件名下到底有多少子文件(子树),所以就难以确定子结点的个数,因此考虑用类似字典树的方式建树。不同的是,字典树的每个结点是一个字符,
而本题的每个结点是一个字符串。
如何将字符串和编号联系起来?显然要用map。第一个问题就解决了。
那么如何组织成一棵树呢?上面说了用类似建trie的方式编号,具体的实现方式自然就是用map数组map<string,int>M[maxn]。每一个M[i]都是一个map,而M[i]可以组织起根节点编号为i的所有子树。
1 #include<iostream> 2 #include<string> 3 #include<map> 4 using namespace std; 5 string t,s; 6 map<string,int>M[20001]; 7 int tot,n,p,pos; 8 void pre(int m,int s){ //m:当前编号,s:前导空格 9 map<string,int>::iterator it; 10 for(it=M[m].begin();it!=M[m].end();++it){ 11 for(int i=0;i<s;i++) cout<<' '; 12 cout<<it->first<<endl; 13 pre(it->second,s+1); 14 } 15 } 16 int main() 17 { 18 cin>>n; 19 while(n--){ 20 int now=0; //当前所在树的结点编号 21 cin>>t; 22 pos=p=0; //将'\'作为分隔符依次抽取子串插入树中 23 while((p=t.find('\\',p))!=-1){ 24 s=t.substr(pos,p-pos); 25 if(!M[now].count(s)) M[now][s]=++tot; 26 now=M[now][s]; 27 pos=++p; 28 } 29 s=t.substr(pos); 30 if(!M[now].count(s)) M[now][s]=++tot; //处理最后一个文件名 31 } 32 pre(0,0); 33 }
如果用it指向M[i]的某个元素(也就是根节点编号为i的某个儿子),it->first就是文件名,it->second就是该儿子的编号,从而可以递归地实现输出。
由于map的插入本身是有序的,故要实现字典序输出,只需要前序遍历即可。