C# 如何解析树的一行字符串表示?
我得到了树的一行字符串表示。树中的键是int。关键点是唯一的(但稀疏)。例如字符串C# 如何解析树的一行字符串表示?,c#,.net,algorithm,data-structures,tree,C#,.net,Algorithm,Data Structures,Tree,我得到了树的一行字符串表示。树中的键是int。关键点是唯一的(但稀疏)。例如字符串 2[5],3[6,12[15,16]] 描述树 2 \-- 5 3 |-- 6 `-- 12 |-- 15 `-- 16 我想用GetChildren方法将单行字符串解析为ChildLookup类,以便 GetChildren(2)返回[5] GetChildren(5)返回[] GetChildren(3)返回[6,12] GetChildren(10)抛出KeyNotFoundExcep
2[5],3[6,12[15,16]]
描述树
2
\-- 5
3
|-- 6
`-- 12
|-- 15
`-- 16
我想用GetChildren方法将单行字符串解析为ChildLookup类,以便
- GetChildren(2)返回[5]
- GetChildren(5)返回[]
- GetChildren(3)返回[6,12]
- GetChildren(10)抛出KeyNotFoundException
当然,您可以构建整个树,但这可能比您需要做的更多。这里有一个ersatz LR lexer/解析器(在Python中,但移植应该很容易)。假设输入有效
#!/usr/bin/env python3
import re
def parse(s):
children = {}
stack = []
for token in re.findall('[+-]?[0-9]+|.', s):
if token == '[':
stack.append(n)
elif token == ']':
del stack[-1]
elif token != ',':
n = int(token)
children[n] = []
if stack:
children[stack[-1]].append(n)
return children
>>> print(parse('2[5],3[6,12[15,16]]'))
{16: [], 2: [5], 3: [6, 12], 5: [], 6: [], 12: [15, 16], 15: []}
您可以编写一个状态机解析器来构建树 开始声明一个
节点
类,如下所示:
public class Node
{
public Node Parent;
public string Value;
public List<Node> SubNodes;
}
Node root = new Node { Parent = null, Value = string.Empty, SubNodes = new List<Node>() };
Node node = root;
foreach (char c in tree)
{
switch (c)
{
case '[': // Start a new node, child of the current node
node = new Node { Parent = node, Value = string.Empty, SubNodes = new List<Node>() };
node.Parent.SubNodes.Add(node);
break;
case ',': // Start a new node, but at the same level of the current node
node = new Node { Parent = node.Parent, Value = string.Empty, SubNodes = new List<Node>() };
node.Parent.SubNodes.Add(node);
break;
case ']': // Back to parent of the current node
node = node.Parent;
break;
default: // Add char to current node value
node.Value += c;
break;
}
}
root
|--2
| |--5
|
|--3
|--6
|--12
|--15
|--16
解析器应该是这样的:
public class Node
{
public Node Parent;
public string Value;
public List<Node> SubNodes;
}
Node root = new Node { Parent = null, Value = string.Empty, SubNodes = new List<Node>() };
Node node = root;
foreach (char c in tree)
{
switch (c)
{
case '[': // Start a new node, child of the current node
node = new Node { Parent = node, Value = string.Empty, SubNodes = new List<Node>() };
node.Parent.SubNodes.Add(node);
break;
case ',': // Start a new node, but at the same level of the current node
node = new Node { Parent = node.Parent, Value = string.Empty, SubNodes = new List<Node>() };
node.Parent.SubNodes.Add(node);
break;
case ']': // Back to parent of the current node
node = node.Parent;
break;
default: // Add char to current node value
node.Value += c;
break;
}
}
root
|--2
| |--5
|
|--3
|--6
|--12
|--15
|--16
最后,您的ChildLookup
如下所示:
var lookup = new ChildLookup(root);
...
class ChildLookup
{
Dictionary<string, Node> nodes;
public ChildLookup(Node node)
{
nodes = new Dictionary<string, Node>();
AddNodes(node);
}
private void AddNodes(Node node)
{
nodes[node.Value] = node;
foreach (var item in node.SubNodes)
AddNodes(item);
}
public IEnumerable<string> GetChildren(string key)
{
if (!nodes.ContainsKey(key)) throw new KeyNotFoundException();
return nodes[key].SubNodes.Select(c => c.Value);
}
}
var lookup=新的子查找(根);
...
类子查找
{
字典节点;
公共子查找(节点)
{
节点=新字典();
添加节点(node);
}
私有void AddNodes(节点节点)
{
节点[node.Value]=节点;
foreach(节点子节点中的变量项)
添加节点(项目);
}
公共IEnumerable GetChildren(字符串键)
{
如果(!nodes.ContainsKey(key))抛出新的KeyNotFoundException();
返回节点[key]。子节点。选择(c=>c.Value);
}
}
我打赌这是Haskell程序员可以在一行中完成的事情。因此,您不想解析整个树,而实际上只查找特定节点的直接后代?在这种情况下,哈希表(映射节点=>list of children)的性能(如果有很多查找)将比实际的树更高。