【树】列出分级文件系统中的目录列程

树形数据结构实现
本文介绍了一种树形数据结构的实现方法,包括节点的创建、插入操作及递归打印等核心功能。通过具体示例展示了如何构建和操作树结构。

第一次写树的数据结构,可能还存在一些小bug

首先是创建树:每个节点包含了第一个孩子和他的兄弟姐妹

typedef char * TreeElement;
typedef struct TreeNode * PtrToNode;
typedef PtrToNode Tree;

struct TreeNode {
	TreeElement element;
	PtrToNode    FirstChild;	// first child
	PtrToNode	 NextSibling; // brother
};

首先创建的是root节点,然后创建第一个孩子和兄弟姐妹

在决定插入孩子还是兄弟姐妹时,需要优先确认父节点AddressToPtr就是用来确定父节点的

static Tree CreateRootTree()
{
	Tree tree =  (Tree)malloc(sizeof(struct TreeNode));
	if(tree==NULL){
		fprintf(stderr,"%s there is no space during malloc struct TreeNode\n", __func__);
		return NULL;
	}

	tree->element = (TreeElement)malloc(sizeof(sizeof(char)*100));
	if(tree->element == NULL){
		fprintf(stderr,"%s there is no space during malloc tree->element\n", __func__);
		return NULL;
	}
	strcpy(tree->element, "usr");
	tree->FirstChild = NULL;
	tree->NextSibling = NULL;
	return tree;
}

static PtrToNode AddressToPtr(char * address, Tree tree)
{
	char *end = strchr(address,'/');//查找/第一次出现的位置
	PtrToNode PtrSameLevel = NULL;
	if(end==NULL){//直接插入当前节点,这是递归的基准情形
		return tree;
	}
	
	// 找到树的源头
	char *next = strchr(end+1,'/');
	char temp_file[100];
	if(next!=NULL){
		int index=0;
		for(char *p=end+1; p!=next;p++){
			temp_file[index]=*p;
			index++;
		}
		temp_file[index]='\0';	
	}else{
		strcpy(temp_file, end+1);
	}
	
	
	//printf("temp_file is %s\n", temp_file);
	if(tree->FirstChild){
		//printf("tree->FirstChild->element is %s\n", tree->FirstChild->element);
		PtrToNode child = tree->FirstChild;
		// 优先查找第一个孩子,然后查找兄弟姐妹
		if(strcmp(child->element,temp_file)==0){
			
			PtrSameLevel = child;
			return AddressToPtr(end+1, PtrSameLevel);
		}
			
		while(child->NextSibling){
			child = child->NextSibling;	
			if(strcmp(child->element,temp_file)==0){
				break;
			}
		}
		
		if(child){
			PtrSameLevel = child;
			return AddressToPtr(end+1, PtrSameLevel);
		}else{
			return NULL;
		}
	}else{
		printf("tree->FirstChild is NULL\n");
		return NULL;
	}
}

static void Insert(char * address, char *filename, Tree tree)
{
	PtrToNode ptrtonode = AddressToPtr(address+1, tree); //找到应该插入的位置
	PtrToNode NewNode = (PtrToNode)malloc(sizeof(struct TreeNode));
	if(NewNode==NULL){
		fprintf(stderr,"%s there is no space during malloc struct TreeNode\n", __func__);
		return;
	}
	NewNode->FirstChild =NULL;
	NewNode->NextSibling = NULL;
	NewNode->element = (TreeElement)malloc(sizeof(char)*100);
	if(NewNode->element==NULL){
		fprintf(stderr,"%s there is no space during malloc tree->element\n", __func__);
		return;
	}
	strcpy(NewNode->element, filename);
	
	PtrToNode child = ptrtonode->FirstChild;
	if(child==NULL){//优先插入第一个孩子
		ptrtonode->FirstChild = NewNode;//这里一定是tree->FirstChild,不能是child,因为child是NULL
	}else{
		// 然后插入兄弟姐妹
		while(child->NextSibling){//找到最后一个兄弟
			child = child->NextSibling;
		}
		child->NextSibling = NewNode;
	}
}

调用如下:

	Tree tree=CreateRootTree();
	
	Insert("/usr", "aaa", tree);  
	Insert("/usr", "bbb", tree);  
	Insert("/usr", "ccc", tree); 
	Insert("/usr", "ddd", tree);
	Insert("/usr", "eee", tree);
	Insert("/usr/eee", "wanger", tree);
	Insert("/usr/bbb", "zhangsan", tree); 
	Insert("/usr/bbb/zhangsan", "lisi", tree); 
	Insert("/usr/bbb/zhangsan/lisi", "lisi1", tree); 
	Insert("/usr/ccc", "lisi", tree); 	

下面是打印树

static void PrintTree(Tree tree, int index)
{
	if(tree){
		while(index--){
			printf("        ");
		}
		printf("%s\n", tree->element);
	}
}

static void ListDirTree(Tree tree, int index)
{
	PrintTree(tree, index);
	Tree tree_node = tree->FirstChild;
	while(tree_node){
		ListDirTree(tree_node, index+1);//这里不能是index++或者++index因为index的值不能改变
		//printf("index is %d\n", index);
		tree_node = tree_node->NextSibling;
	}
}

循环中使用递归可将一个树打印出来


由此可见,定义树的一种自然的方法就是递归


<think>我们将在C++中实现一个列出分级系统中目录的例。这通常涉及到遍历目录,并打印出目录结构(包括子目录)。我们可以使用递归的方式来实现,同时为了显示层级,我们会在每一层添加缩进。 由于C++标准库中没有直接提供遍历目录的函数,我们将使用操作系统相关的API。但是,为了跨平台,我们可以使用C++17引入的`<filesystem>`库,它提供了操作文件系统的标准方式。 以下是一个使用C++17的`std::filesystem`递归列出目录结构的例: 步骤: 1. 包含必要的头文件:<filesystem>和<iostream> 2. 使用std::filesystem::recursive_directory_iterator来遍历目录 3. 对于每个遍历到的条目,判断是否是目录,如果是则打印(同时根据深度进行缩进) 注意:我们也可以使用非递归的方式(如使用栈)来实现,但使用递归迭代器可以简化代码。 我们将编写一个函数,接受一个路径作为参数,然后递归地列出所有目录。 但是注意:用户要求的是“分级系统中目录的例”,所以我们只关心目录,不关心文件。 代码示例: */ #include <iostream> #include <filesystem> #include <string> namespace fs = std::filesystem; // 函数:打印目录 void print_directory_tree(const fs::path& path, const std::string& indent = "") { try { // 首先,打印当前目录 std::cout << indent << "[" << path.filename().string() << "]" << std::endl; // 遍历当前目录 for (const auto& entry : fs::directory_iterator(path)) { if (entry.is_directory()) { // 如果是目录,递归打印,并增加缩进 print_directory_tree(entry.path(), indent + " "); } } } catch (const fs::filesystem_error& e) { std::cerr << "Error accessing path: " << e.what() << std::endl; } } int main() { std::string path_str; std::cout << "Enter the directory path: "; std::getline(std::cin, path_str); fs::path dir_path(path_str); if (!fs::exists(dir_path)) { std::cerr << "Path does not exist." << std::endl; return 1; } if (!fs::is_directory(dir_path)) { std::cerr << "Path is not a directory." << std::endl; return 1; } print_directory_tree(dir_path); return 0; } /* 说明: 1. 我们定义了一个函数print_directory_tree,它接受一个路径和缩进字符串(用于表示层级)。 2. 首先打印当前目录的名称(用方括号括起来表示是目录)。 3. 然后遍历当前目录下的每一项,如果遇到子目录,就递归调用自己,并增加缩进(这里每次递归增加两个空格)。 4. 使用try-catch块来捕获可能出现的异常(如权限不足等)。 注意:这个序只打印目录,不打印文件。 但是,上面的序在遍历时,对于每个目录,我们使用directory_iterator,然后递归进入子目录。实际上,我们也可以使用recursive_directory_iterator,但那样会遍历所有条目(包括文件),而我们只需要目录。所以这里我们选择递归调用。 然而,上面的递归方式可能会因为目录过深而导致栈溢出。对于非常深的目录结构,我们可以使用非递归的方法(例如使用栈)来避免。但一般情况下,目录深度不会太深,递归是可行的。 非递归版本(使用栈)的示例: 我们可以使用栈来模拟递归过,每次遇到一个目录,就将其子目录压入栈中,并记录当前深度。 非递归版本代码示例: */ #include <iostream> #include <filesystem> #include <string> #include <stack> #include <vector> namespace fs = std::filesystem; struct DirectoryInfo { fs::path path; int depth; // 当前深度,用于缩进 }; void print_directory_tree_non_recursive(const fs::path& root_path) { std::stack<DirectoryInfo> stack; stack.push({root_path, 0}); while (!stack.empty()) { DirectoryInfo current = stack.top(); stack.pop(); // 打印当前目录(根据深度缩进) std::string indent(current.depth * 2, ' '); // 每层缩进两个空格 std::cout << indent << "[" << current.path.filename().string() << "]" << std::endl; try { // 遍历当前目录的所有条目,将子目录按逆序压入栈中(这样正序弹出) std::vector<fs::path> subdirs; for (const auto& entry : fs::directory_iterator(current.path)) { if (entry.is_directory()) { subdirs.push_back(entry.path()); } } // 注意:栈是后进先出,为了保持原来的顺序(比如字母顺序),我们可以逆序压栈 // 这样弹出时就是正序了。但注意:directory_iterator的顺序是未指定的,所以如果需要排序,可以自行排序。 // 这里我们按文件名的字母顺序逆序压栈,这样弹出时就是正序。 // 排序(按文件名升序) std::sort(subdirs.begin(), subdirs.end()); // 逆序压栈 for (auto it = subdirs.rbegin(); it != subdirs.rend(); ++it) { stack.push({*it, current.depth + 1}); } } catch (const fs::filesystem_error&) { // 忽略无法访问的目录 } } } // 在main函数中,我们可以调用print_directory_tree_non_recursive /* 注意:非递归版本使用栈,避免了递归深度过大导致的栈溢出问题。同时,我们通过记录深度来实现缩进。 用户可以根据需要选择递归或非递归版本。 另外,我们只遍历了目录,忽略了文件。 如果用户需要同时列出文件和目录,可以修改代码。 但是问题要求是“目录的例”,所以我们只列出目录。 相关问题: 1. 如何在C++中获取目录的创建时间? 2. 如何过滤目录(例如只列出特定扩展名的目录)? 3. 如何处理符号链接目录? 4. 如何计算目录的大小(包括子目录)? 5. 如何异步遍历大型目录结构?</think>### C++ 实现分级目录遍历的例 在 C++ 中遍历分级目录系统,可以使用 `<filesystem>` 库(C++17 标准引入),它提供了跨平台的目录操作功能。以下是两种实现方式: #### 方法 1:递归实现(简单直观) ```cpp #include <iostream> #include <filesystem> #include <string> namespace fs = std::filesystem; // 递归打印目录结构 void print_directory(const fs::path& path, int depth = 0) { try { // 打印当前目录(带缩进) std::cout << std::string(depth * 2, ' ') << "[" << path.filename().string() << "]" << std::endl; // 遍历子项 for (const auto& entry : fs::directory_iterator(path)) { if (entry.is_directory()) { // 递归处理子目录 print_directory(entry.path(), depth + 1); } else { // 打印文件(带缩进) std::cout << std::string((depth + 1) * 2, ' ') << "- " << entry.path().filename().string() << std::endl; } } } catch (const fs::filesystem_error& e) { std::cerr << "访问错误: " << e.what() << std::endl; } } int main() { std::string root_path = "/path/to/your/directory"; // 替换为你的目录路径 print_directory(root_path); return 0; } ``` #### 方法 2:非递归实现(使用栈,避免深度递归风险) ```cpp #include <iostream> #include <filesystem> #include <stack> #include <string> namespace fs = std::filesystem; void print_directory_non_recursive(const fs::path& root) { std::stack<std::pair<fs::path, int>> stack; stack.push({root, 0}); // {路径, 当前深度} while (!stack.empty()) { auto [current_path, depth] = stack.top(); stack.pop(); // 打印当前目录 std::cout << std::string(depth * 2, ' ') << "[" << current_path.filename().string() << "]" << std::endl; try { // 反向遍历(保证输出顺序) std::vector<fs::directory_entry> entries; for (const auto& entry : fs::directory_iterator(current_path)) { entries.push_back(entry); } // 先压栈文件,再压栈目录(LIFO) for (auto it = entries.rbegin(); it != entries.rend(); ++it) { if (it->is_directory()) { stack.push({it->path(), depth + 1}); } else { std::cout << std::string((depth + 1) * 2, ' ') << "- " << it->path().filename().string() << std::endl; } } } catch (const fs::filesystem_error& e) { std::cerr << "访问错误: " << e.what() << std::endl; } } } int main() { std::string root_path = "/path/to/your/directory"; // 替换为你的目录路径 print_directory_non_recursive(root_path); return 0; } ``` ### 关键特性说明 1. **跨平台支持** 使用 C++17 标准库 `<filesystem>`,在 Windows/Linux/macOS 均可运行[^1]。 2. **层级可视化** 通过缩进显示目录结构: ``` [parent] [child] - file.txt - document.pdf ``` 3. **错误处理** 捕获 `filesystem_error` 异常,处理权限不足或路径错误等情况。 4. **路径表示** - `fs::path::filename()` 获取当前目录名 - `fs::directory_iterator` 遍历目录内容 ### 编译说明 - 需要支持 C++17 的编译器(GCC 8+/Clang 7+/MSVC 2017+) - 编译时添加链接选项:`-lstdc++fs`(GCC)或 `/std:c++17`(MSVC) ### 性能优化建议 - 对于超大型目录,非递归方法可避免栈溢出风险 - 使用 `fs::directory_options::skip_permission_denied` 忽略无权限目录 - 异步遍历:结合 `<thread>` 实现并行处理(需注意线安全)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值