首页 > 编程语言 >上机编程“文件树”学习交流

上机编程“文件树”学习交流

时间:2023-12-21 11:35:34浏览次数:31  
标签:Node 上机 parent 编程 交流 child nodes root string

在某OS的文件系统中(同一目录下的目录和文件不会重名),假设当前目录为根目录,给定若干个已有路径(目录或文

件),其格式如下:

·         输入均为根目录下的路径,且不会重复给出;

·         路径中目录或文件名仅包含字母、数字和分隔符/;

·         路径结尾带/表示目录,否则是文件。例如 var/log/是目录,etc/profile是文件。

请按照以下规则,将输入的路径整理成树状结构并输出:

·         同一父目录下的目录或文件按字典序升序输出,大小写敏感

·         第一层目录或文件无需缩进;后续每深入一层,需要多缩进两个空格

·         输出时目录和文件都不含/

解答要求时间限制:1000ms, 内存限制:256MB

输入

第一行一个整数 num,表示路径的数量,取值范围 [1,1000]

接下来 num 行,每行一个路径字符串,长度范围 [1,255]

用例保证输入的路径合法,且不会以/开头

输出

按行输出树状结构的路径

样例

输入样例 1

5

usr/local/lib64

GAMES

usr/DRIVERS

home

var/log/

输出样例

GAMES

home

usr

  DRIVERS

  local

    lib64

var

  log

提示样例 1

输出内容,及对应的路径,如下图所示:
https://oj.rnd.huawei.com/public/upload/f7fa2c0b29.png

输入样例 2

4

ROOT/A

drv

root/b/

ROOT/

输出样例

ROOT

  A

drv

root

  b

大小写敏感,所以ROOT 和 root 是两个目录,按字典序大写在前。

 

2.     题目分析

题目理解:

题目要求将扁平的目录结构,转换为层状显示,例如输入:

usr/local/lib64

usr/DRIVERS

要求输出:

usr

  DRIVERS

  local

lib64

题目说了,同一目录下的目录和文件不会重名,意味着不同路径下可能存在同名目录、文件。

关键需求分析:

l  由于一行输入的路径可能包含分隔符’/’、需要拆分为多个路径,所以输出的行数可能比输入行数多。

l  同一父目录下的目录或文件按字典序升序输出,即按’/’拆分前就需要排序,输出后的路径的归属关系不能打乱。

l  当前行路径和上一行路径前面相同部分不输出、而是以空格代替。

解题思路:

主要有两种思路:

1)        构造、遍历树

涉及到路径操作的问题,通常可以用树这种数据结构,所以容易想到的解法就是定义一个树的结构,例如:

struct Node {

    节点名称;

    Node *children; 子节点

} Node;

Node具体的成员定义有多种不同的实现方式,例如常见的有:

C++

Java

Python

Go

class Node {

public:

    string name;

    vector<Node> children;

};

static class Trie {

    ...

    TreeMap<StringTrie> children;

}

class Tree:

    def __init__(selfvallevel = 0):

        self.val = val

        self.level = level

        self.children = {}   

type Node struct {

    name     string

    children Nodes

    idx      map[string]int

}

根据输入参数构造出树后,再深度遍历就可以得到输出结果。

2)        按字符’/’拆分字符串后,生成一个映射表

根据题目样例1的提示,将输出和路径这两列的顺序调换一下,可以得到如下表格

 

唯一路径名

显示名称

usr

usr

usr/DRIVERS

  DRIVERS

usr/local

  local

usr/local/lib64

lib64

 

可以看到,只要我们整理出所有不重复的全路径名、排序之后,就可以得到第一列内容;然后再根据路径中’/’的个数计算空格的数量就得到最终的显示名称。

不重复的全路径名可以通过TreeMap/TreeSet/map/set/dict等容器来实现。

 

map建树+DFS遍历

 

package main

import (
    "fmt"
    "sort"
    "strings"
)

type DirNode struct {
    name     string
    level    int
    children []*DirNode
}

func buildTree(routeList []string, dirTreeList map[string]*DirNode) {
    // 大小写敏感,拆分之前需排序,字典序升序
    sort.Slice(routeList, func(i, j int) bool {
        return routeList[i] < routeList[j]
    })
    for _, route := range routeList {
        routeNameList := strings.Split(route, "/")
        for index, routeName := range routeNameList {
            if routeName != "" {
                if _, exist := dirTreeList[routeName]; !exist {
                    dirTreeList[routeName] = &DirNode{
                        name:  routeName,
                        level: index,
                    }
                }
            }
        }
    }
    fmt.Println(dirTreeList)
}

type Node struct {
    level int
    child map[string]*Node
}

func NewNode(level int) *Node {
    return &Node{
        level: level,
        child: make(map[string]*Node),
    }
}

const G_BLANK_NUM = 2

func Dfs(root *Node, res *[]string) {
    if len(root.child) == 0 {
        return
    }

    var keys []string
    for k := range root.child {
        keys = append(keys, k)
    }
    sort.Strings(keys)

    for _, k := range keys {
        v := root.child[k]
        blank := strings.Repeat(" ", root.level*G_BLANK_NUM)
        cur := blank + k
        *res = append(*res, cur)
        if v != nil {
            Dfs(v, res)
        }
    }
}

func GetTreeFormat(fileTreeList []string) []string {
    root := NewNode(0)
    for _, file := range fileTreeList {
        names := strings.Split(file, "/")
        cur := root
        for _, name := range names {
            if _, ok := cur.child[name]; !ok {
                cur.child[name] = NewNode(cur.level + 1)
            }
            cur = cur.child[name]
        }
    }

    var result []string
    Dfs(root, &result)
    return result
}

func main() {
    routeList := []string{
        "usr/local/lib64",
        "GAMES",
        "usr/DRIVERS",
        "home",
        "var/log/",
    }

    //dirTreeList := make(map[string]*DirNode, len(routeList))
    //buildTree(routeList, dirTreeList)
    //for _, dirTree := range dirTreeList {
    //    for i := 0; i < dirTree.level; i++ {
    //        fmt.Print(" ")
    //    }
    //    fmt.Println(dirTree.name)
    //}

    ans := GetTreeFormat(routeList)
    for _, result := range ans {
        fmt.Println(result)
    }
}
View Code

 

map建多叉树总结:

 

func buildTree(parent, child string, treeNodeMap map[string]*TreeNode) {
	father, ok := treeNodeMap[parent]
	if !ok {
		father = &TreeNode{name: parent}
		treeNodeMap[parent] = father
	}
	children, ok := treeNodeMap[child]
	if !ok {
		children = &TreeNode{name: child}
		treeNodeMap[child] = children
	}
	father.child = append(father.child, children)
}

 

变种1

  

func buildTree(pairs [][]string) *Node {
    nodes := make(map[string]*Node)
    for _, pair := range pairs {
        parent, child := pair[0], pair[1]
        if nodes[parent] == nil {
            nodes[parent] = &Node{val: parent}
        }
        if nodes[child] == nil {
            nodes[child] = &Node{val: child}
        }
        nodes[parent].children = append(nodes[parent].children, nodes[child])
    }
    return nodes["root"]
}

  

变种2

func buildTree(parent, child int, statuses []int, nodes map[int]*dirNode) {
	if nodes[child] == nil {
		nodes[child] = &dirNode{id: child, status: statuses[child], userId: map[int]bool{}}
	}
	if nodes[parent] == nil && parent != -1 {
		nodes[parent] = &dirNode{id: parent, status: statuses[parent], userId: map[int]bool{}}
	}
	if parent != -1 {
		nodes[parent].children = append(nodes[parent].children, nodes[child])
		nodes[child].parent = nodes[parent]
	}
}

 

变种3

    root := NewNode(0)
	for _, file := range fileTreeList {
		names := strings.Split(file, "/")
		cur := root
		for _, name := range names {
			if _, ok := cur.child[name]; !ok {
				cur.child[name] = NewNode(cur.level + 1)
			}
			cur = cur.child[name]
		}
	}

  

 

建二叉树

// 构建二叉树
func buildTree(nodeValues []int) *Node {
	if len(nodeValues) == 0 || nodeValues[0] == math.MaxInt32 {
		return nil
	}
	root := &Node{value: rune(nodeValues[0])}
	queue := []*Node{root}
	i := 1
	for len(queue) > 0 && i < len(nodeValues) {
		node := queue[0]
		queue = queue[1:]
		// 左子节点
		if nodeValues[i] != math.MaxInt32 {
			node.left = &Node{value: nodeValues[i]}
			queue = append(queue, node.left)
		}
		i++
		// 右子节点
		if i < len(nodeValues) && nodeValues[i] != math.MaxInt32 {
			node.right = &Node{value: nodeValues[i]}
			queue = append(queue, node.right)
		}
		i++
	}
	return root
}

  

 

标签:Node,上机,parent,编程,交流,child,nodes,root,string
From: https://www.cnblogs.com/gongxianjin/p/17918611.html

相关文章

  • 数据库编程大赛:一条SQL计算扑克牌24点
    你是否在寻找一个平台,能让你展示你的SQL技能,与同行们一较高下?你是否渴望在实战中提升你的SQL水平,开阔你的技术视野?如果你对这些都感兴趣,那么本次由NineData主办的《数据库编程大赛》,将是你的最佳选择!大赛奖品本次数据库编程大赛的奖项安排:一等奖(1人)、二等奖(2人)、三等奖(3人)、......
  • 出错处理封装函数 - 使Socket编程更安全可靠
    导语       在Socket编程中,错误处理是至关重要的一环。通过封装出错处理函数,我们可以提高代码的可读性和可维护性,增加代码的重用性,统一管理错误信息,提高系统的稳定性和可靠性。本文将详细介绍为什么要进行出错处理函数的封装,并探讨如何使Socket编程更加安全可靠。   正......
  • Python异步编程之yield from
    yieldfrom简介yieldfrom是Python3.3后新加的语言结构,可用于简化yield表达式的使用。yieldfrom简单示例:>>>defgen():...yieldfromrange(10)...>>>g=gen()>>>next(g)0>>>next(g)1>>>yieldfrom用于获取生成器中的值,是对yield使用的一种......
  • 实验7 文件应用编程
    task4#define_CRT_SECURE_NO_WARNINGS1#include<stdlib.h>#include<stdio.h>#defineN100intmain(){FILE*fp;charn,*p;intcount=0;fp=fopen("data4.txt","r");while(feof(fp)==0){n=fgetc(fp);if(n!=''&......
  • 【ECMAScript】提高JavaScript编程效率:掌握ES8的新特性和语法
    前言ECMAScript8,也称为ES8或ES2017,是JavaScript语言的最新标准。它在ES6的基础上进一步扩展了JavaScript的功能,为开发者提供了更多的工具和语法来编写高效、可维护的代码。本篇博客将详细介绍ES8的各种新特性及其用法,帮助读者更好地了解和掌握这个强大的语言标准。正文内容1.......
  • 啊哈编程
    啊哈编程成立于2017年9月,在一年多的时间里,我们已经发展成一个集青少年编程steam教育体系研发,编程教学工具(APP)开发、线上线下教学服务与咨询为一体的综合性教育平台。啊哈编程是啊哈C、啊哈算法作者啊哈磊带领团队创立的编程品牌,旗下有啊哈编程在线、啊哈编程学员、啊哈C软件、啊......
  • Java 并发编程在生产应用场景及实战
    背景介绍为什么需要学习Java并发?从提升性能角度来说提升了对CPU的使用效率:目前生产的服务器大多数都是多核,标配的机器都是8C/16G。操作系统会将不同的线程分配给不同的核心处理,理论上,有多少核心就有多少个线程并行执行。如果没有并发编程,CPU的利用率将极大的浪费,假设当......
  • 实验7 文件应用编程
    实验任务4:文件简单应用程序源码1#include<stdio.h>23intmain(){4FILE*fp;5longsize;6intc;7intcount=0;8fp=fopen("C:\\data\\data4.txt","rb");9while((c=fgetc(fp))!=EOF){10......
  • 泛型编程
    泛型编程:使用模板,编写跟类型无关的代码。一个函数和类的时候,针对不同类型需要写很多重复的代码。函数:比如我们想实现交换int、double、char等等各种类型对象的函数swap类:比如想实现一个数据结构栈Stack,Stack的多个对象,st1存intst2存double,等等。在没有模板之前,我们得针对......
  • 警惕境外的诈骗分子——以学术交流或学术合作之名的非法分子
    刚刚收到一个估计是境外分子发来的邮件,这种发给军工研究所和科研单位的寻求学术合作的邮件大概率是诈骗或其他什么非法目的的:注意这个邮箱地址:[email protected]说是要进行学术合作,还说能提供基金号,这种的一看就是非法分子,估计大概率是境外的非法势力的渗透,对......