【问题标题】:Traverse a Spaghetti Stack and reverse to a tree遍历 Spaghetti Stack 并反转到树
【发布时间】:2018-05-05 01:19:17
【问题描述】:

我有一个 Spaghetti Stack(一个 N 叉树数据结构,其中子节点具有指向父节点的指针) - 从数据库接收。

从数据库收到的“堆栈”只是一个包含所有节点的列表,因此可以 里面有多个堆栈。

节点是数据库中的记录,其中 parent.id 是另一个相同类型记录的 ForeignKey。

class Node_Category:
  def __init__(self, value):
    self.value = value
    parent_id = id

结构是这样的:

Category 1
 -Category 1_1
  --Category 1_1_1
 -Category 1_2
Category_2
Category_3
 -Category 3_1
 -Category 3_2

我需要什么:

现在我知道孩子的父母了。从父节点开始,我需要了解他的孩子。

所以我需要遍历“Spaghetti Stack”,将父节点中的连接添加到子节点,这样我就可以从父节点遍历到子节点。

父母可以有 0 个、一个或多个孩子。

因为我不知道堆栈的深度,所以我尝试递归。

我还认为有必要进行某种形式的记忆,因为通过数组循环一个父级的父级会获得多次访问。

我尝试了什么:

   def _recurse_for_parents(self, category, path=None):

    if path is None:
        path = []
    path.append(category)
    if category.parent:
        return self._recurse_for_parents(category.parent, path)
    return path

 for record in categories:
            self._recurse_for_parents(category)

问题:

在循环中我可以点击父级、一级子级、二级等:

Child1_L2-Child1_L1->parent; Child1_L1->parent; parent->Null
Child1_L1->parent; parent->Null
Child2_L1->parent; parent->Null

所以,我在不同深度多次走同一条路。 此外,对于每条路径,我都需要将他的父级链接添加回子级。

【问题讨论】:

  • 您需要知道所有节点的子节点,还是一次只知道给定节点?
  • 适用于所有节点。我正在考虑创建一个列表列表,例如:[parent [parent-child []],[parent-child [child, child]],我需要将此信息表单后端也传递给前端
  • 那么你的问题是什么?
  • 我需要一个解决方案/算法/示例来使用递归和记忆化来做到这一点。我多次尝试简单的递归,但没有找到合适的解决方案。因为我从一个包含所有节点的大列表开始,所以我以类似的递归方式输入,我不知道如何添加路径。循环中的父级可以命中 children2-children1-parent, children1->parent,->parent;这是1-1-1的关系。每个父母有多个孩子,深度 5 是不行的。

标签: python algorithm recursion stack tree-traversal


【解决方案1】:

这在概念上似乎很简单。我看不出递归实现在哪里特别有用。迭代解决方案很简单。我将概述基本思想。

我假设给你一个包含 N 个节点的数组,并且每个节点都有一个 ID。

我要做的第一件事是创建一个字典,以 ID 为键,值是具有以下结构的新节点类型:

NewNode
    Id - the node's id
    Children - a list of some type that contains the ids of the node's children
    Whatever other data the database gives you.

对于列表中的每个节点,在字典中查找父节点,并将该节点添加到父节点的子节点列表中。

当您浏览上述步骤中的列表时,您应该在一个没有父 ID 的节点上运行。这就是根源。如果没有这样的节点或有多个节点,则您的数据无效。

无论如何,您在字典中查找该节点的 id 并将其保存为根。

示例

假设你有两棵树:

           100                  200
         /     \             /   |   \
      101      120         201  210  220
       |      /   \         |         |
      102   121   122      202       221
     /   \               /  |  \
   103   110           203 204 205
    |
   104

所以你有这些节点:

ID      Parent
104     103
103     102
102     101
101     100
100     NULL
110     102
121     120
120     100
122     120
203     202
202     201
201     200
204     202
205     202
210     200
221     220
220     200
200     NULL

我的建议是您从该列表中创建一个字典,以节点 ID 为键。每个节点都有一个children 列表。

现在,从列表中的第一项开始,查找父节点,并将节点添加到父节点的子列表中。因此,对于第一项,您会看到节点 104 的父节点为 103。您将对节点 104 的引用添加到 103 的子列表中。

然后您继续到列表中的下一个节点。完成后,您的字典如下所示:

ID      Parent  Children
104     103     []
103     102     [104]
102     101     [103]
101     100     [102]
100     NULL    [101,110,120]
110     102     []
121     120     []
120     100     [121,122]
122     120     []
203     202     []
202     201     [203,204,205]
201     200     [202]
200     NULL    [201,210,220]
204     202     []
205     202     []
210     200     []
221     220     []
220     200     [221]

您的字典现在包含倒置树。您可以扫描字典,查找 Parent 值为 NULL 的节点。这些是你树的根。每个根都有一个对其子节点的引用数组,这些子节点有对其子节点的引用,等等。

【讨论】:

  • 我用更多数据编辑我的问题;希望现在更清楚了。我有更多的根,每个Top Category都是一个根,我是从叶子开始的。
  • @user3541631 如果你有多个根,那么你就有多个树,字典中没有父 ID 的每个节点都被认为是一棵单独的树。无论您遍历节点的顺序如何,我描述的算法都有效。
  • 是的,但我在一个大列表中收到所有内容,没有分开,我不知道哪一棵是一棵,或者列表中有多少棵树;您能否在您的解决方案中添加更多内容,我不知道如何适应我的情况
【解决方案2】:

一个简单的解决方案可能是以下一个,假设您的节点由整数表示,并且您的数组是这样的(或任何可迭代的)所有节点,然后:

adjacencies = []
for node in tree : # iterate on all your nodes
    adjacencies += [(node.parent_id, node)]

然后要获取给定节点的子节点,您只需按如下方式进行处理:

def get_children (parent :int, adjacencies :list) -> set:
    return {child for (parent, child) in adjacencies}

如果您想要更精确的解决方案,您需要向我提供有关您的实施的更多信息;然后我会编辑。

【讨论】:

  • 我的节点不是整数,是具有属性的对象。数据库中有记录,其中的父项是另一个相同类型记录的 ForeignKey。
  • 然后编辑您的问题并添加一段代码,显示您如何访问树的父节点,以及您必须以哪种方式迭代您的节点。
  • 我用更多数据编辑我的问题;希望现在更加清晰
猜你喜欢
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
  • 2016-08-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多