主要思路:
1.定义结构体node,包含1)名字name(2)指向下级目录指针ctl(3)指向下级文件指针file(4)指向同级目录或文件指针next(取决于它本身是目录还是文件)。
定义一个全局的指针ptr,指向上一个处理完毕的结点,比如一开始在输入“a\b\c”的中,ptr一开始指向root,从root开始处理a,处理完后ptr指向a,然后从ptr(即a)开始处理b,处理完后ptr指向b,再从ptr(即b)开始处理c。
2.处理一行数据时,字符串后带\的为目录,否则为文件。
3.假设插入一个目录类型结点s,从某一结点(设为x)开始,如果x的目录为空,直接插入;如果不为空,从x的指向的目录a开始,s与a比较,如果小于(按字典序排在前面),则在x和a之间插入s即可,否则,s继续跟a的next结点b比较,如果s小于b了,则在a与b之间插入s,以此类推……如果到链表遍历完毕都没有找到比s大的结点,说明s最大,需要放在最后,在遍历结束后直接让链表最后一个结点指向s即可。在s插入完毕后,ptr指向s,表明下一个结点的处理是从ptr结点开始的,如本段开头s的插入是从x结点开始的。
如果s跟x的目录重名了,则不需要插入s,直接令ptr指向x即可,然后开始下一个结点的处理(那就是从x,即ptr开始处理了)。
4.假设插入一个文件类型结点s,方法与上述插入目录结点时类似,只是插入文件结点时,是小于(即按字典序规则排在前面),等于(即重名)的时候插入,因为当
文件重名时,不能说只有一个文件,有n个文件重名那就是有n个文件,所以s仍然需要插入,这里跟目录的插入不同,重名的目录即使有多个也是只看成一个的,所以不需要重复插入了。
5.还要注意,在a和c之间插入b时,需要分情况处理,如果a与b同级,是a的next指向b;如果a比高一级,则a的ctl或者file指针指向b。
6.使用Print()函数递归输出
1 void Print(int cnt, struct node* p) 2 { 3 struct node* s = p; 4 if (!p)return; 5 print_sp(cnt); 6 cnt += 2; 7 cout << p->name << endl; 8 while (s->ctl)//输出完目录 9 { 10 Print(cnt, s->ctl); 11 s->ctl = s->ctl->next; 12 } 13 while (p->file)//再输出文件 14 { 15 Print(cnt, p->file); 16 p->file = p->file->next; 17 } 18 }
1 #include <iostream> 2 #include <string> 3 #include <cstring> 4 5 using namespace std; 6 typedef struct node//文件或目录的结点 7 { 8 char name[300]; 9 struct node* ctl;//指向下一级的目录 10 struct node* file;//指向下一级的文件 11 struct node* next;//指向同级的文件或目录 12 }; 13 struct node root;//定义根节点为全局变量 14 struct node* ptr = NULL;//定义一个全局的指向node的指针 15 //ptr的作用:每次插入结点后,(针对同一行的结点)ptr指向新插入的结点,使得下一次插入的时候能直接从ptr开始处理 16 //如果没有新插入结点(只有一种情况,即有同名目录的时候,ptr直接指向同名的那个结点,然后直接退出插入函数 17 //当处理完一行数据的时候,ptr指向root,因为每一行都是从root开始处理的 18 bool smaller(char s1[], char s2[])//按照字典序规则比较两个字符串,s1<s2返回true 19 { 20 for (int i = 0; i < 300; i++) 21 { 22 if (s1[i] == s2[i]) 23 { 24 for (int j = i; j < 300; j++) 25 { 26 if (s1[j] == ‘\0‘ && s2[j] != ‘\0‘) 27 { 28 return true; 29 } 30 if (s1[j] != ‘\0‘ && s2[j] == ‘\0‘) 31 { 32 return false; 33 } 34 if (s1[j] < s2[j]) 35 { 36 return true; 37 } 38 else if (s1[j] > s2[j]) 39 { 40 return false; 41 } 42 } 43 } 44 else if (s1[i] < s2[i])return true; 45 else return false; 46 } 47 } 48 bool equal(char s1[], char s2[])//比较两个字符串,相等即返回true 49 { 50 for (int i = 0; i < 300; i++) 51 { 52 if (s1[i] != s2[i]) 53 { 54 return false; 55 } 56 } 57 return true; 58 } 59 void ins_file(char name[])//插入一个文件结点 60 { 61 struct node* s = new struct node; 62 s->ctl = s->file = s->next = NULL; 63 strcpy(s->name, name); 64 if (!ptr->file) 65 { 66 ptr->file = s; 67 } 68 else 69 {//遍历文件结点,将s插入到第一个比它大的结点中(字典序排序规则) 70 struct node* p = ptr->file;//初始化为ptr的file指向的结点 71 struct node* p_pio = ptr;//前驱结点 72 int flag = 0;//标志,没有插入,置0;插入了s结点,置1 73 while (p) 74 {//重名的文件也要当成两个文件,但是重名目录不需要 75 if (smaller(s->name, p->name) || equal(s->name, p->name))//如果小于或等于,就可以头插入 76 { 77 flag = 1; 78 s->next = p; 79 if (p_pio->file == p)//如果上一个结点是上级结点 80 p_pio->file = s;//则令上一个结点的file指向s 81 else 82 p_pio->next = s;//如果是同级结点,则令它的next指向s 83 break; 84 } 85 p_pio = p;// 86 p = p->next; 87 } 88 if (flag == 0)//flag==0,说明上面过程没有插入,所以这里直接将s放最后面 89 { 90 p_pio->next = s;//如果没有比s小的,即s应该排在最后 91 } 92 } 93 ptr = s;//ptr需要指向新插入的结点 94 } 95 void ins_ctl(char name[])//插入一个目录结点 96 { 97 struct node* s = new struct node; 98 s->ctl = s->file = s->next = NULL; 99 strcpy(s->name, name); 100 if (!ptr->ctl) 101 { 102 ptr->ctl = s; 103 } 104 else 105 { 106 struct node* p = ptr->ctl; 107 struct node* p_pio = ptr; 108 int flag = 0; 109 while (p) 110 { 111 if (equal(s->name, p->name)) 112 {//文件插入中这一步不需要,因为多同名的文件是要当成多个的,而同名目录可以共用 113 ptr = p;//s与p同名,所以不用插入s了,直接令ptr指向p,直接return,然后处理下个结点时就会从p开始 114 return; 115 } 116 else if (smaller(s->name, p->name)) 117 {//以下方法与插入文件时相同 118 flag = 1; 119 s->next = p; 120 if (p_pio->ctl == p) 121 p_pio->ctl = s; 122 else 123 p_pio->next = s; 124 break; 125 } 126 p_pio = p; 127 p = p->next; 128 } 129 if (flag == 0) 130 { 131 p_pio->next = s; 132 } 133 } 134 ptr = s; 135 } 136 void print_sp(int n)//输出空格的函数 137 { 138 for (int i = 0; i < n; i++) 139 cout << ‘ ‘; 140 } 141 int d = 0; 142 int cnt = -2; 143 struct node* p = &root; 144 void Print(int cnt, struct node* p)//输出最终结果的函数 145 { 146 struct node* s = p; 147 if (!p)return; 148 print_sp(cnt); 149 cnt += 2;//输出空格后,cnt增加2 150 cout << p->name << endl;//输出名字 151 //用递归输出,先输出完目录,再输出文件的思想 152 while (s->ctl) 153 { 154 Print(cnt, s->ctl); 155 s->ctl = s->ctl->next; 156 } 157 while (p->file) 158 { 159 Print(cnt, p->file); 160 p->file = p->file->next; 161 } 162 } 163 int main() 164 { 165 root.ctl = root.file = root.next = NULL; 166 strcpy(root.name, "root"); 167 int n; cin >> n; 168 for (int i = 0; i < n; i++) 169 { 170 char s[300]; 171 char s1[300]; 172 cin >> s; 173 ptr = &root;//ptr初始化为root,因为每行输入都是从root开始处理的 174 //全局指针ptr永远代表某一结点插入时开始处理的位置 175 for (int j = 0, k = 0; j < 300; k++, j++) 176 { 177 if (s[j] == ‘\\‘) 178 { 179 s1[j] = ‘\0‘; 180 ins_ctl(s1); 181 k = -1; 182 memset(s1, 0, sizeof(char) * 300); 183 continue; 184 } 185 else if (s[j] == ‘\0‘) 186 { 187 if (s[j - 1] == ‘\\‘)break;//这一句作用是处理如“a\b\”等最后的目录下没有文件的情况 188 s1[j] = ‘\0‘; 189 ins_file(s1); 190 k = -1;//设为-1是因为本次循环结束进入下一次循环k+1==0,刚好从0开始 191 memset(s1, 0, sizeof(char) * 300); 192 break; 193 } 194 else 195 { 196 s1[k] = s[j];//将输入一行中的某个结点的名字放到s1中 197 } 198 } 199 } 200 Print(0, &root); 201 return 0; 202 }
原文地址:https://www.cnblogs.com/2020R/p/12578616.html