Laboratorio básico 4-2.6 Árbol de directorios (30 puntos)

 

En el archivo ZIP, se guardan las rutas relativas y los nombres de todos los archivos y directorios comprimidos. Al abrir archivos ZIP con software GUI como WinZIP, la estructura de árbol del directorio se puede reconstruir a partir de esta información. Escriba un programa para reconstruir la estructura de árbol del directorio.

Formato de entrada:

La entrada primero da un entero positivo N (≤10 4), que representa el número de archivos y directorios en el archivo ZIP. Siguientes N líneas, cada línea tiene la ruta relativa y el nombre del archivo o directorio en el siguiente formato (cada línea no excede los 260 caracteres):

  • Los caracteres de la ruta y el nombre solo incluyen letras en inglés (distingue entre mayúsculas y minúsculas);
  • El símbolo "\" solo aparece como separador de ruta;
  • El directorio termina con el símbolo "\";
  • No hay elementos de entrada duplicados;
  • El tamaño total de la entrada no supera los 2 MB.

Formato de salida:

Suponga que todas las rutas son relativas al directorio raíz. Comenzando desde el directorio raíz, al generar, cada directorio primero genera su propio nombre, luego genera todos los subdirectorios en orden lexicográfico y luego genera todos los archivos en orden lexicográfico. Tenga en cuenta que al generar la salida, se deben usar espacios para la sangría de acuerdo con la relación relativa de los directorios.Cada nivel de directorio o archivo tiene una sangría de 2 espacios más que el nivel anterior.

Muestra de entrada:


Salida de muestra:

De hecho, este problema no necesita construir un árbol múltiple, solo use la notación del hijo izquierdo y del hermano derecho enseñada por el maestro Él. La estructura de datos es una lista enlazada binaria. Finalmente, el recorrido de preorden del árbol binario puede resolver este problema. Por supuesto, cómo construir un árbol es un punto difícil. Publicaré el código aquí primero, y escribiré las ideas de análisis específicas y algunas trampas de esta pregunta en unos días.

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

La idea central del logro:

Permítanme mencionar algunas precauciones. La prioridad de inserción de los directorios debe ser mayor que la de los archivos. De hecho, los directorios son equivalentes a nodos no hoja y los archivos equivalen a nodos hoja. Por lo tanto, no importa cuán pequeño sea el orden lexicográfico de un archivo, siempre irá a un directorio. Retroceder.

Otro punto es que solo procesamos una línea de cadenas cada vez, y cada vez insertamos los directorios y archivos de esta línea uno por uno desde la raíz del nodo raíz.

El último punto es que el orden lexicográfico de la misma prioridad de inserción es el primero.

El siguiente es un proceso específico de construcción de un árbol con un caso como ejemplo. Después de leer este proceso, si sabe cómo escribir un programa, ¡escríbalo rápidamente!

Para resumir todo el proceso de establecimiento es este:

Primero construya un árbol binario con solo la raíz del nodo raíz.

Luego lea en una línea de cuerda. Tenga en cuenta que una línea de cadena puede tener varios directorios, pero como máximo un solo archivo.

Primero establezca una posición de puntero para que apunte a la raíz.

De acuerdo con esta regla, primero buscamos el primer directorio en la cadena, y luego buscamos la existencia de este directorio en el árbol binario con raíz en pos. Si es así, usamos pos para registrar la dirección del directorio que ya existe en el árbol binario. Si este directorio no existe en el árbol binario, buscamos la ubicación donde este directorio debe colocarse en el árbol binario. El proceso de búsqueda comienza con el niño en el nodo raíz y camina hacia la derecha a lo largo de la cadena. Tenga en cuenta que vamos completamente hacia la derecha. Cada vez que comparamos la prioridad de un nodo Nodo en la cadena (la llamada prioridad aquí especificamos que la prioridad del directorio es 1, la prioridad del archivo es 0, 1 es mayor que 0, por lo que la prioridad del directorio es mayor), si desea insertar Si la prioridad es mayor que el nodo de la cadena o la prioridad es la misma pero el orden lexicográfico del nodo a insertar es menor, se puede insertar directamente frente al nodo de la cadena, la prioridad es menor que el nodo de la cadena o la prioridad es la misma Pero si el orden lexicográfico es mayor que el nodo Nodo en la cadena, continuaremos buscando hacia atrás a lo largo de esta cadena . El caso más extremo es encontrar el final de la cadena, luego el final de la cadena es la posición donde traemos el elemento insertado.   Finalmente, inserte el primer directorio en el árbol binario y actualice pos a la posición insertada.

Luego leeremos en el segundo directorio y repetiremos los pasos anteriores.

Continúe leyendo en el tercer directorio. . .

Después de leer todos los directorios, debemos verificar si hay algún archivo detrás del último directorio. Si lo hay, insértelo en el subárbol enraizado en pos. Tenga en cuenta que el archivo es diferente del directorio, y es posible que el directorio ya esté en el subárbol. Existe, por lo que primero debemos verificar si el directorio existe en el árbol binario, pero no es necesario verificar el archivo, solo necesitamos insertarlo directamente en el subárbol enraizado en pos.

Hasta ahora hemos completado el procesamiento de una línea de cuerdas. Hay un pequeño detalle sobre cómo interceptar un directorio o archivo de una cadena, solo necesitamos usar la función substr ().

Entonces procesamos la siguiente línea de cadenas de la misma manera hasta que se procesan todas las cadenas.

La siguiente figura simula el proceso de cómo insertar un directorio y un archivo:

 

Marco del programa:

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

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

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

Código:

#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;
}

 

Supongo que te gusta

Origin blog.csdn.net/yiwaite/article/details/100823604
Recomendado
Clasificación