寻找一种Python的方式来将树构建为字典,使我们最终得到{13: [11, 8], 11: [], 3: [], 6: [3], 8: [6]}
由于我知道根节点,我的方法是循环遍历具有值为13的条目,并连接它们,然后将这些条目视为根,依此类推。
请注意,没有排序。为了区分,我知道根节点(某个数字),并可以从中确定。
是否有更好的方法?
寻找一种Python的方式来将树构建为字典,使我们最终得到{13: [11, 8], 11: [], 3: [], 6: [3], 8: [6]}
由于我知道根节点,我的方法是循环遍历具有值为13的条目,并连接它们,然后将这些条目视为根,依此类推。
请注意,没有排序。为了区分,我知道根节点(某个数字),并可以从中确定。
是否有更好的方法?
set
来跟踪已添加到字典中的元素,我们可以在 O(n) 时间内解决此问题。一般思路是循环遍历节点,检查节点是否当前在图中,如果是,则在添加到字典时知道它是父节点。from collections import defaultdict
class MyTree:
def __init__(self, data):
self.data = defaultdict(list)
self.seen = set()
for node in data:
self.add_node(node)
for el in self.seen:
if el not in self.data:
self.data[el] = []
def add_node(self, el):
x, y = el
if y in self.seen:
self.data[y].append(x)
else:
self.data[x].append(y)
self.seen.update(el)
实际应用:
arr = [[1,2], [1,8], [5, 8], [3, 5]]
x = MyTree(arr)
print(x.data)
defaultdict(<class 'list'>, {1: [2, 8], 8: [5], 5: [3], 2: [], 3: []})
def dfs(es, s):
graph = {}
for x, y in es:
graph.setdefault(x, set()).add(y)
graph.setdefault(y, set()).add(x)
tree, stack = {}, [s]
while stack:
parent = stack.pop()
children = graph[parent] - tree.keys()
tree[parent] = list(children)
stack.extend(children)
return tree
edges = [[1, 2], [5, 8], [1, 8], [3, 5]]
print(dfs(edges, 1))
输出
{8: [5], 1: [8, 2], 2: [], 3: [], 5: [3]}
O(N + E)
,其中N
是节点数,E
是边数。虽然速度较慢,但更简单的方法是:egdes = [[1, 2], [1, 8], [5, 8], [3, 5]]
tree = {}
sources = {1}
while sources:
parent = sources.pop()
children = [t for s, t in egdes if (s == parent and t not in tree)] + \
[s for s, t in egdes if (t == parent and s not in tree)]
tree[parent] = children
sources.update(children)
print(tree)
输出
{8: [5], 1: [2, 8], 2: [], 3: [], 5: [3]}
while sources:
parent = sources.pop()
children = [y if x == parent else x for x, y in edges if parent in (x, y)]
edges = [edge for edge in edges if parent not in edge]
tree[parent] = children
sources.update(children)
输出
{8: [5], 1: [2, 8], 2: [], 3: [], 5: [3]}
递归方法:
d = [[1,2], [1,8], [5, 8], [3, 5]]
def t(d, r):
o = {r: []}
n = []
for e in d:
if r in e:
if e[1] == r:
e = e[::-1]
o[e[0]].append(e[1])
else:
n.append(e)
for i in o[r]:
o.update(t(n, i))
return o
print(t(d, 1))
这将输出:
{1: [2, 8], 2: [], 8: [5], 5: [3], 3: []}
你可以使用广度优先搜索:
import collections
data = [[1,2], [1,8], [5, 8], [3, 5]]
def bfs(d, _start = lambda x:x[0][0]):
_queue, _result, _seen = collections.deque([_start(d)]), collections.defaultdict(list), []
while _queue:
v = _queue.popleft()
r = [i[0] if i[-1] == v else i[-1] for i in d if v in i]
_r = [i for i in r if i not in _seen]
_result[v].extend(_r)
_queue.extend(_r)
_seen.extend(_r+[v])
return _result
print(bfs(data))
输出:
defaultdict(<class 'list'>, {1: [2, 8], 8: [5], 5: [3], 2: [], 3: []})
d = [[1,2], [1,8], [5, 8], [3, 5]]
def t(d, r):
o = {r: []}
while d:
e = d.pop(0)
if e[1] in o:
e = e[::-1]
if e[0] in o:
o[e[0]].append(e[1])
o[e[1]] = []
else:
d.append(e)
return o
print(t(d, 1))
这将输出:
{1: [2, 8], 2: [], 8: [5], 5: [3], 3: []}