7-30 目录树 (30分)

主要思路:

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()函数递归输出

扫描二维码关注公众号,回复: 10204454 查看本文章
 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 }

猜你喜欢

转载自www.cnblogs.com/2020R/p/12578616.html
今日推荐