Basic Lab 4-2.6 Directory Tree (30 points)

 

In the ZIP archive file, the relative paths and names of all compressed files and directories are kept. When opening ZIP archive files with GUI software such as WinZIP, the tree structure of the directory can be reconstructed from this information. Please write a program to rebuild the tree structure of the directory.

Input format:

The input first gives a positive integer N (≤10​4​​), which represents the number of files and directories in the ZIP archive. Next N lines, each line has the relative path and name of the file or directory in the following format (each line does not exceed 260 characters):

  • The characters in the path and name only include English letters (case sensitive);
  • The symbol "\" only appears as a path separator;
  • The directory ends with the symbol "\";
  • There are no duplicate input items;
  • The entire input size does not exceed 2MB.

Output format:

Assume that all paths are relative to the root directory. Starting from the root directory, when outputting, each directory first outputs its own name, then outputs all subdirectories in lexicographic order, and then outputs all files in lexicographic order. Note that when outputting, spaces should be used for indentation according to the relative relationship of the directories. Each level of directory or file is indented by 2 spaces more than the previous level.

Input sample:


Sample output:

In fact, this problem does not need to build a polytree, just use the left child and right brother notation taught by Teacher He. The data structure is a binary linked list. Finally, the preorder traversal of the binary tree can solve this problem. Of course, how to build a tree is a difficult point. I will post the code here first, and I will write the specific analysis ideas and some pitfalls of this question in a few days.

-------------------------------------------------------------------------------------------------------------------------------

The core idea of ​​achievement:

Let me mention some precautions. The insertion priority of directories must be higher than that of files. In fact, directories are equivalent to non-leaf nodes, and files are equivalent to leaf nodes. Therefore, no matter how small the lexicographic order of a file is, it will always go to a directory. Move back.

Another point is that we only process one line of strings each time, and each time we insert the directories and files of this line one by one from the root node root.

The last point is that the lexicographic order of the same insertion priority is first.

The following is a specific process of building a tree with a case as an example. After reading this process, if you know how to write a program, write it quickly!

To sum up the whole establishment process is this:

First build a binary tree with only the root node root.

Then read in a line of string. Note that a line of string can have several directories but at most only one file.

First set a pointer pos to point to root.

According to this rule, we first find the first directory in the string, and then look for the existence of this directory in the binary tree rooted at pos. If so, we use pos to record the address of the directory that already exists in the binary tree. If this directory does not exist in the binary tree, then we look for the location where this directory should be placed in the binary tree. The search process starts with the child at the root node and walks to the right along the chain. Note that we are going all the way to the right. Each time we compare the priority of a node Node on the chain (the so-called priority here we specify that the directory priority is 1, the file priority is 0, 1 is greater than 0, so the directory priority is higher), if you want to insert If the priority is higher than the node on the chain or the priority is the same but the lexicographic order of the node to be inserted is smaller, it can be directly inserted in front of the node on the chain, the priority is lower than the node on the chain or the priority is the same But if the lexicographic order is greater than the node Node on the chain, we will continue to search backward along this chain . The most extreme case is to find the end of the chain, then the end of the chain is the position where we bring the inserted element.   Finally, insert the first directory into the binary tree and update pos to the inserted position.

Then we will read in the second directory and repeat the above steps.

Continue reading into the third directory. . .

After reading all the directories, we need to check if there are any files behind the last directory. If there is, insert it into the subtree rooted at pos. Note that the file is different from the directory, and the directory may already be in the subtree. Exist, so we must first check whether the directory exists in the binary tree, but the file does not need to be checked, we just need to insert it directly into the subtree rooted at pos.

So far we have completed the processing of a line of strings. There is a small detail about how to intercept a directory or file from a string. We just need to use the substr() function.

So we process the next line of strings in the same way until all the strings are processed.

The following figure simulates the process of how to insert a directory and file:

 

Program framework:

int main()
{
	建立一颗只有根结点root的二叉树;

	for(i=0; i<N; i++)
	{
		读入一行字符串str;
		设置一个指针pos指向root;
		while(str中还有目录还没插入二叉树中)
		{
			读入一个目录;
			将目录插入以pos为根的子树中,并把pos更新为插入的地址;
		}
		if(有文件未读入)
		{
			读入文件;
			把文件插入以pos为根结点的子树;
		}
	}

	前序遍历以root为根结点的二叉树;
	return 0;
}

Code:

#include<stdio.h>
#include<string.h>
#include<string>
#include<stack>
#include<iostream>
using namespace std;
struct TreeNode//左孩子右兄弟的二叉树表示法
{
	string str;
	TreeNode* child;//左孩子
	TreeNode* sibling;//右兄弟
	int priority;//priority==0表示为文件,priority==1为目录,目录的插入优先级比文件高
};
typedef TreeNode* Position;
typedef Position BinTree;
Position createNode(string s, int priority)//创建一个新结点并初始化
{
	Position Node = new TreeNode;
	Node->str = s;
	Node->child = Node->sibling = NULL;
	Node->priority = priority;
	return Node;
}
Position insert(BinTree root, string s, int priority)//插入结点函数,把结点作为root的孩子插入,并返回插入的位置
{
	if(root->child == NULL)//如果root的根本没有儿子的话,那么直接插入在root儿子的位置即可。
	{
		root->child = createNode(s,priority);
		return root->child;
	}
	Position tmpNode = root->child,father = root;
	//没有return,说明root有儿子,开从root的儿子开始循链找插入位置
	//如果待插入结点的优先级小于tmpNode的优先级,或者tmpNode的优先级和待插入结点优先级一致,但待插入结点的字典序大于tmpNode的字典序,要继续循链寻找。
	//注意因为循链寻找的的极端过程是找到了链的最右边,即可能tmpNode可能会为NULL,所以要加入判断语句tmpNode!=NULL,即当找到链的末尾时就要退出,否则会产生段错误。
	while(tmpNode!=NULL&&((priority<tmpNode->priority)||(tmpNode->priority==priority&&s>tmpNode->str)))
	{
		father = tmpNode;
		tmpNode = tmpNode->sibling;
	}
	//当我们退出循环时有3种情况,1、找到了链的末尾,说明结点应该插入链的末尾处;2、待插入的目录已经存在于二叉树中,我们直接返回目录所在位置即可,无需插入;
	//3、找到了应该插入的位置。这3中情况分别对应下面的if else语句。
     if(tmpNode==NULL)//1、找到了链的末尾,说明结点应该插入链的末尾处;
		{
			Position Node = createNode(s,priority);
			Node->sibling = father->sibling;
			father->sibling = Node;
			return Node;
		}
	if(tmpNode->priority==priority&&s==tmpNode->str)//2、待插入的目录已经存在于二叉树中,我们直接返回目录所在位置即可,无需插入;
		return tmpNode;
	else//3、找到了应该插入的位置。
	{
		Position Node = createNode(s,priority);
		if(father->str == root->str)//但这里又有一个细节,插入位置是在root的child的位置和root的child的sibling的位置的插入方法是不一样的。
		{
			Node->sibling = father->child;
			father->child = Node;
		}
		else
		{
			Node->sibling = father->sibling;
			father->sibling = Node;
		}
		return Node;
	}
}
void PreorderTraversal(BinTree BT,int layer)//前序遍历输出,注意需要一个参数layer来控制缩进,递归和非递归都可以,非递归版本我也写了但是没有递归这么漂亮,想要非递归版本可以给我留言
{
	int i;
	int childlayer,siblinglayer;
	if(BT)
	{
		for(i=0; i<layer; i++)
			printf("  ");
		childlayer = layer+1;
		siblinglayer = layer;
		cout<<BT->str<<endl;
		PreorderTraversal(BT->child,childlayer);
		PreorderTraversal(BT->sibling,siblinglayer);
	}
}
int main()
{
	int N,i,bgn,end,j;
	string str;
	Position pos;
	BinTree root = createNode("root",1);//建立只有一个根结点的二叉树,根结点也是目录所以优先级为1
	scanf("%d\n",&N);
	for(i=0; i<N; i++)
	{
		getline(cin,str); pos = root; bgn = end = 0;//bgn记录目录或文件的首字符位置,end记录目录或文件最后一个字符后面一个字符的位置
		for(j=0; j<str.length(); j++)
		{
			if(str[j] == '\\')
			{
				end = j;
				pos = insert(pos,str.substr(bgn,end-bgn),1);
				bgn = end+1;
			}
		}
		if(str[bgn]!='\0')//读完所有目录后,判断字符串中是否还有文件,如果有,读入文件
		{
			insert(pos,str.substr(bgn,str.length()-bgn),0);
		}
	}
	PreorderTraversal(root,0);//前序遍历输出
	return 0;
}

 

Guess you like

Origin blog.csdn.net/yiwaite/article/details/100823604