我有一个文本文件,其内容如下:
a.b.c.d
a.c
a.d
a.x.y.z
a.x.y.a
a.x.y.b
a.subtree
我想把它变成一棵树:
a
/ / \ \ \
b c d x subtree
| |
c y
| / | \
d z a b
修改:需要将具有两个a.x.y.a
节点的a
路径视为单独的实体。基本上a.x.y.a
就是路径。
我们可以像这样查看输入文件:
Level0.Level1.Level2...
我尝试在python中执行此操作(我也熟悉java,也希望java答案)但不知怎的,我在逻辑上无法做到这一点。
我的基本树结构有点像这样:
class Tree:
def __init__(self,data):
self.x = data
self.children = []
逻辑有点像这样:
for line in open("file","r"):
foos = line.split(".")
for foo in foos:
put_foo_in_tree_where_it_belongs()
我该如何处理这个问题?
此外,如果有任何 java 库帮助我这样做,我也可以转向java。只需要完成这个。
答案 0 :(得分:3)
基本算法应该是这样的:
def add_path(root, path):
if path:
child = root.setdefault(path[0], {})
add_path(child, path[1:])
root = {}
with open('tree.txt') as f:
for p in f:
add_path(root, p.strip().split('.'))
import json
print json.dumps(root, indent=4)
输出:
{
"a": {
"x": {
"y": {
"a": {},
"z": {},
"b": {}
}
},
"c": {},
"b": {
"c": {
"d": {}
}
},
"d": {},
"subtree": {}
}
}
答案 1 :(得分:2)
我想我会这样做:
class Node(object):
def __init__(self,data=None):
self.children = []
self.data = data
def add_from_dot_str(self,s):
elems = s.split('.')
if self.data is None:
self.data = elems[0]
elif self.data != elems[0]:
raise ValueError
current = self
for elem in elems[1:]:
n = Node(elem)
current.children.append(n)
current = n
@classmethod
def from_dot_file(cls,fname):
with open(fname) as fin:
root = Node()
for line in fin:
root.add_from_dot_str(line.strip())
return root
def __str__(self):
s = self.data
s += ','.join(str(child) for child in self.children)
return s
print Node.from_dot_file('myfilename')
答案 2 :(得分:1)
这是一个Java版本(未经测试)。请注意,这是完整的。它不需要输入字符串的任何初始转换。它还保留了树节点的插入顺序:
public class Node implements Iterable<Node> {
private String name;
private Map<String, Node> children = new LinkedHashMap<String, Node>();
public Node(String name) {
this.name = name;
}
public String getName() { return this.name; }
public Iterator<Node> iterator() { return children.values().iterator(); }
private Node lookupOrAddChild(String name) {
Node child = children.get(name);
if (child = null) {
child = new Node(name);
children.put(name, child);
}
return child;
}
private void addLine(String line) {
int pos = line.indexOf(".");
if (pos < 0) {
lookupOrAddChild(line);
} else {
node = lookupOrAddChild(line.subString(0, pos));
node.addLine(line.substring(pos + 1));
}
}
public static Node buildTree(String[] input) {
Node node = new Node("");
for (String line : input) {
node.addLine(line);
}
// This assumes the input forms exactly one "tree"
return node.children.values().iterator().next();
}
答案 3 :(得分:1)
以下是使用Java实现Trie数据结构
import java.util.*;
class Tree
{
class Node
{
String data;
ArrayList<Node> children;
public Node(String data)
{
this.data = data;
children = new ArrayList<Node>();
}
public Node getChild(String data)
{
for(Node n : children)
if(n.data.equals(data))
return n;
return null;
}
}
private Node root;
public Tree()
{
root = new Node("");
}
public boolean isEmpty()
{
return root==null;
}
public void add(String str)
{
Node current = root;
StringTokenizer s = new StringTokenizer(str, ".");
while(s.hasMoreElements())
{
str = (String)s.nextElement();
Node child = current.getChild(str);
if(child==null)
{
current.children.add(new Node(str));
child = current.getChild(str);
}
current = child;
}
}
public void print()
{
print(this.root);
}
private void print(Node n)
{
if(n==null)
return;
for(Node c : n.children)
{
System.out.print(c.data + " ");
print(c);
}
}
}
要验证实现,请使用以下类
import java.io.*;
public class TestTree
{
public static void main(String[] args) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Tree t = new Tree();
String s;
int i=7;
while(i-->0)
{
s = br.readLine();
t.add(s);
}
System.out.println("Tree constructed!");
t.print();
}
}
添加方法的算法
1.它以字符串作为输入
它在句号(。)
分割字符串
3.对于获得的每个子字符串(在拆分之后),检查该值,如果该字符串已经存在于树中,则它遵循该路径,否则它将在当前级别插入新字符串(新节点)
代码适用于输入
a.b.c.d
b.c.d.e
a.e.f.a
c.d.f.c
etc
这意味着第一级可以有任何字符串
注意:强>
在TestTree.java中,我设置i=7
仅用于测试目的
您可以提供7个输入测试用例
a.b.c.d
a.c
a.d
a.x.y.z
a.x.y.a
a.x.y.b
a.subtree
Print方法使用前序遍历打印树的数据。它仅用于验证目的,您可以根据需要进行调整。
希望这有帮助! :)
答案 4 :(得分:0)
仅仅为了“想要java答案”,我提供了一个Java解决方案:) 要使用,请解析输入,将它们推入队列,调用insertFromRoot(Queue)
public class CustomTree {
private TreeNode root;
public class TreeNode {
String value;
Map<String, TreeNode> children = new HashMap<String, TreeNode>();
public TreeNode(String val) {
this.value = val;
}
}
public void insertFromRoot(Queue<String> strings) {
if (strings != null && !strings.isEmpty()) {
if (root == null) {
root = new TreeNode(strings.poll());
} else {
if (!root.value.equals(strings.poll())) {
throw new InvalidParameterException("The input doesnt belong to the same tree as the root elements are not the same!");
}
}
}
TreeNode current = root;
while (!strings.isEmpty()) {
TreeNode newNode = null;
if (current.children.containsKey(strings.peek())) {
newNode = current.children.get(strings.poll());
} else {
newNode = new TreeNode(strings.poll());
current.children.put(newNode.value, newNode);
}
current = newNode;
}
}
}
编辑:
简单用法:
public static void main(String[] args) {
Queue<String> que = new LinkedList<String>();
que.add("a");
que.add("b");
que.add("c");
Queue<String> que2 = new LinkedList<String>();
que2.add("a");
que2.add("b");
que2.add("d");
CustomTree tree = new CustomTree();
tree.insertFromRoot(que);
tree.insertFromRoot(que2);
}