Python中最简单的树数据结构,可以轻松地在两个方向上进行遍历

Python中最简单的树数据结构,可以轻松地在两个方向上进行遍历,python,data-structures,Python,Data Structures,我需要一个最简单的数据结构实现,它可以在父->子对象和子对象->父对象方向上遍历;因此,理想情况下,孩子也应该持有对父母的引用 我在想一本字典,在字典里孩子们只需引用他们的父母,类似这样: # define the root node a = {'name': 'trunk', 'value': 0, 'parent': None, 'children': []} # add child a['children'].append({'name': 'branch-1', 'value': 1,

我需要一个最简单的数据结构实现,它可以在父->子对象和子对象->父对象方向上遍历;因此,理想情况下,孩子也应该持有对父母的引用

我在想一本字典,在字典里孩子们只需引用他们的父母,类似这样:

# define the root node
a = {'name': 'trunk', 'value': 0, 'parent': None, 'children': []}
# add child
a['children'].append({'name': 'branch-1', 'value': 1,
                      'parent': a, 'children': []})
# and so on...

这样做安全吗?循环引用可能会影响垃圾收集?这样做有意义吗?什么更简单?

您可以创建一个节点类

基本结构看起来是这样的,不过老实说,你也可以用dicts来实现。我个人觉得课程看起来更干净

class Node(object):
    def __init__(self):
        self.parent = None # Single object
        self.child = []  # Array of objects
        self.name = None
        self.data = None 
其余的取决于你的需要。有些函数可能需要内置到类中,或者如果使用哈希,则在脚本中内置为方法

更新:获取特定节点并更新其值/名称/内容 有你 删除:获取特定节点并将其从树中删除。如果 执行此操作时,请确保将已删除的节点连接到子节点 已删除父节点。 插入:它在树中获取一个特定点并添加一个新节点 我喜欢它。这将更新节点周围的父节点和子节点。 更新子项:将子项追加到node.child数组。应该是 从更新父进程调用,因为这两个进程是自引用的。 更新父级:从parent.child数组中删除self。增加自我 新建_parent.child数组。 如果您想方便地引用节点的特定部分,可以制作一个哈希映射作为一种目录

node_tree_map = {}
node_tree_map[node.name] = node 
# node_tree_map['name'] would allow you quick access to bob's
# parent/children/value 
# just by knowing the name but without having to traverse 
# the whole tree to find it 
如果有必要,上面的内容将允许您轻松深入特定节点


顺便说一句,删除树或哈希映射中引用的节点将使垃圾收集不再成为问题

您将创建一个节点类

基本结构看起来是这样的,不过老实说,你也可以用dicts来实现。我个人觉得课程看起来更干净

class Node(object):
    def __init__(self):
        self.parent = None # Single object
        self.child = []  # Array of objects
        self.name = None
        self.data = None 
其余的取决于你的需要。有些函数可能需要内置到类中,或者如果使用哈希,则在脚本中内置为方法

更新:获取特定节点并更新其值/名称/内容 有你 删除:获取特定节点并将其从树中删除。如果 执行此操作时,请确保将已删除的节点连接到子节点 已删除父节点。 插入:它在树中获取一个特定点并添加一个新节点 我喜欢它。这将更新节点周围的父节点和子节点。 更新子项:将子项追加到node.child数组。应该是 从更新父进程调用,因为这两个进程是自引用的。 更新父级:从parent.child数组中删除self。增加自我 新建_parent.child数组。 如果您想方便地引用节点的特定部分,可以制作一个哈希映射作为一种目录

node_tree_map = {}
node_tree_map[node.name] = node 
# node_tree_map['name'] would allow you quick access to bob's
# parent/children/value 
# just by knowing the name but without having to traverse 
# the whole tree to find it 
如果有必要,上面的内容将允许您轻松深入特定节点


顺便说一句,删除树或哈希映射中引用的节点将使垃圾收集不再成为问题

一个简单的树节点类,可以双向遍历:

class Tree(object):
    def __init__(self, data, children=None, parent=None):
        self.data = data
        self.children = children or []
        self.parent = parent

    def add_child(self, data):
        new_child = Tree(data, parent=self)
        self.children.append(new_child)
        return new_child

    def is_root(self):
        return self.parent is None

    def is_leaf(self):
        return not self.children

    def __str__(self):
        if self.is_leaf():
            return str(self.data)
        return '{data} [{children}]'.format(data=self.data, children=', '.join(map(str, self.children)))

> t = Tree('foo')
> bar = t.add_child('bar')
> baz = t.add_child('baz')
> print(t)
'foo [bar, baz]'

> print(bar.parent)
'foo [bar, baz]'

一个简单的树节点类,可以双向遍历:

class Tree(object):
    def __init__(self, data, children=None, parent=None):
        self.data = data
        self.children = children or []
        self.parent = parent

    def add_child(self, data):
        new_child = Tree(data, parent=self)
        self.children.append(new_child)
        return new_child

    def is_root(self):
        return self.parent is None

    def is_leaf(self):
        return not self.children

    def __str__(self):
        if self.is_leaf():
            return str(self.data)
        return '{data} [{children}]'.format(data=self.data, children=', '.join(map(str, self.children)))

> t = Tree('foo')
> bar = t.add_child('bar')
> baz = t.add_child('baz')
> print(t)
'foo [bar, baz]'

> print(bar.parent)
'foo [bar, baz]'

有人可能会说,简单意味着维护或遍历结构所需的代码量很小。另一个论点可以简单地认为是空间使用量较少。另一种解释是考虑操作的时间复杂性来定义简单。你是对的,客观地定义并不总是容易的。我想我的意思是,它的活动部分最少,并且尽可能接近语言中的基本数据结构。显然,没有太难使用…如果孩子们只引用父母,就很难从父母转移到孩子。有几个问题。每个节点是否有唯一的值?你熟悉创建类吗?是的,我熟悉类,我知道如何用类和弱引用实现类似的东西,我真的在寻找一个更轻量级的解决方案。家长有自己孩子的名单,有什么更好的解决办法吗?@ExperimentsWithCode谢谢,我想我犯了一个错误,没有在这里更具体。我的需求非常简单,就是:从根开始构建树,偶尔从一个节点向上遍历几层来阅读内容。因此,没有更新,没有删除,只构建树,然后移动和读取。实际上,我计划用这种方式包装ElementTree对象,我只能使用stdlib版本。无父引用:能够查看几个父引用以交叉检查依赖项。尽管如此,我还是喜欢你的答案,也许是因为我太过努力地避免类……有人可能会说,简单意味着维护或遍历结构所需的代码很少。另一个论点可以简单地认为是空间使用量较少。可以考虑另一种解释
呃,操作的时间复杂性定义很简单。好吧,你们是对的,客观地定义它并不总是容易的。我想我的意思是,它的活动部分最少,并且尽可能接近语言中的基本数据结构。显然,没有太难使用…如果孩子们只引用父母,就很难从父母转移到孩子。有几个问题。每个节点是否有唯一的值?你熟悉创建类吗?是的,我熟悉类,我知道如何用类和弱引用实现类似的东西,我真的在寻找一个更轻量级的解决方案。家长有自己孩子的名单,有什么更好的解决办法吗?@ExperimentsWithCode谢谢,我想我犯了一个错误,没有在这里更具体。我的需求非常简单,就是:从根开始构建树,偶尔从一个节点向上遍历几层来阅读内容。因此,没有更新,没有删除,只构建树,然后移动和读取。实际上,我计划用这种方式包装ElementTree对象,我只能使用stdlib版本。无父引用:能够查看几个父引用以交叉检查依赖项。尽管如此,我还是喜欢你的答案,也许是因为我太过努力地避免上课……我以此作为答案,喜欢你从极简主义课程开始,然后采取教育性的方法来布置选项。查找特定节点的混合解决方案也是一个不错的选择,我将来可能会使用它。非常感谢。我把这个作为答案,喜欢你从极简主义课程开始,然后用教育性的方法来布置选项。查找特定节点的混合解决方案也是一个不错的选择,我将来可能会使用它。非常感谢。