【问题标题】:Efficient algorithm for converting an array of depths into a Tree将深度数组转换为树的高效算法
【发布时间】:2012-08-27 16:58:01
【问题描述】:

我有一个存储过程,它返回按树组织的名称的平面列表。为了传达谁是有深度值的父级,因此 5 条记录(最多 3 级)的结果如下所示:

Depth|Name
----------
    0|Ford
    1|Compact Cars
    2|Pinto
    1|Trucks
    2|H-Series

我试图通过读取深度值从这个数组中构造一棵树。有没有一些明显的算法可以从这样的数据序列中构造一棵树?我添加 C# 标记是因为我愿意接受 LINQy 解决此问题的方法,尽管通用的计算机科学答案会非常有帮助。

这是我目前的尝试:

class Record
{
  public string Name{ get; set; }
  public List<Record> children { get; set; }
}

var previousLevel = 0;
var records = new List<Record>();

foreach (var thing in TreeFactory.fetch(dao))
{
  if(this.Depth == 0) {
    //Root node
  } else if(thing.Depth > previousLevel) {
    //A Child of the last added node
  } else if(thing.Depth < previousLevel) {
    //A Cousin of the last added node
  } else {
    //A Sibling of the of the last added node
  }
  previousLevel = this.Depth;
}

我所说的“高效”是指最多包含 200,000 个元素的列表大小和最多可扩展到 100 个级别的树,所以实际上我只是在寻找更容易推理的东西。

【问题讨论】:

  • 我当前的代码以一个简单的 List 开头,其中 Record 包含一个名为 Children 的 List。然后我保留先前深度的副本并进行测试。如果新的深度等于前一个它是兄弟,如果它大于则 ti 是一个孩子,如果它小于它是最近添加的父级的兄弟。我说“尝试”是因为代码变得相当混乱。
  • 投反对票是因为问题的模糊性还是以福特汽车为例?
  • 我猜 Pinto 从来没有经历过他们过去容易着火的时期。
  • 当您说您需要一个高效的解决方案时,您的数据集有多大?您是否真的有数十万个项目要添加,或者数千个类似的列表要填充,还是您只是因为“效率总是好的”而这么说。

标签: c# algorithm tree


【解决方案1】:

这里不需要递归。我相信最快的方法是:

public static TreeView TreeFromArray(Item[] arr)
{
    var tv = new TreeView();
    var parents = new TreeNodeCollection[arr.Length];
    parents[0] = tv.Nodes;

    foreach (var item in arr)
    {
        parents[item.Depth + 1] = parents[item.Depth].Add(item.Name).Nodes;
    }

    return tv;
}

项目是任何具有深度和名称信息的东西:

public class Item
{
    public int Depth;
    public string Name;
}

当使用我自己的 TreeNode 实现时,为了简化过程并去除不必要的功能,这些功能会减慢整个过程,并稍微改变方法以适应这些变化,我想出了这个:

类:

    public class Node
    {
        public string Name;
        public List<Node> Childs = new List<Node>();
    }

    public class Item
    {
        public int Depth;
        public string Name;
    }

实施:

    public static Node TreeFromArray(Item[] arr)
    {
        var tree = new Node();

        var parents = new Node[arr.Length];
        parents[0] = tree;

        foreach (var item in arr)
        {
            var curr = parents[item.Depth + 1] = new Node {Name = item.Name};
            parents[item.Depth].Childs.Add(curr);
        }

        return tree;
    }

结果:

使用给定数据:900 毫秒内 1,000,000 次

【讨论】:

  • @Servy 我说不需要,不需要。
  • @YoryeNathan 好的...那为什么要添加它?我没有看到任何使用它的解决方案,甚至没有引用它。
  • 嗯...是的,这只是我脑海中闪现的第一件事,所以我认为这将是一个明显的解决方案。确实,确实没有必要提及。
  • 除了递归的需要或不需要的性质之外,我正在制定实施这个解决方案,我遇到了一些麻烦。我认为 foreach 块需要根节点的特殊情况,否则第一个节点将添加一个子节点到父节点[0]
  • @JasonSperske 这个想法是树的根节点将作为子节点保存所有零深度。如果您知道只有一个零深度节点(并且是第一个),那么您可以将 parents[0] 设置为它,而不是新的(然后是无用的)根音符(或树)。
【解决方案2】:
public void AddNode(Tree tree, Node nodeToAdd, int depth)
{
  //you might need to add a special case to handle adding the root node
  Node iterator = tree.RootNode;  
  for(int i = 0; i < depth; i++)
  {
    iterator = iterator.GetLastChild(); //I assume this method won't exist, but you'll know what to put here
  }

  iterator.AddChild(nodeToAdd);
}

这有点像伪代码。它没有添加错误处理,我假设代码部分存在方法,我想你可以自己弄清楚。

【讨论】:

    【解决方案3】:

    这个数组看起来像是原始树结构的从左到右的“展平”。如果可以安全地假设,那么方法很简单:

    For each element in the array
       If the depth of the element is less than or equal to the "current node"
          traverse upwards to the parent until current depth = element depth -1
       Create a child node of the current node
       Traverse to that node as the new "current" node
    

    【讨论】:

      【解决方案4】:

      成分:

      1. 允许子节点的类。
      2. 此类类型的堆栈。
      3. 此类类型的数组或列表。
      4. 用于存储当前深度的 int。
      5. 持有我们当前感兴趣的项目的本地人。

      方法。

      1. 从列表中取出您的第一项。将其放入堆栈中。将0 存储为当前深度。
      2. 依次从列表中取出每个剩余的项目。看它的深度。如果深度等于或小于当前深度,则从堆栈中弹出(currentdepth - depth + 1)项,并在堆栈中窥视以获取新的当前项。使我们的新项成为“当前项”的子项,使其成为当前项,使其深度成为当前深度。

      在编译器中以 200°C 或 Gas-mark 6 烘烤 300 毫秒,或直至金黄色。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-25
        • 1970-01-01
        • 2012-07-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多