【问题标题】:Recursively search nested lists; Returning parent递归搜索嵌套列表;返回父母
【发布时间】:2011-07-03 09:00:22
【问题描述】:

这是此帖子的后续帖子:Recursively search nested lists

我一直在尝试修改代码以允许我返回位于任何子项的父项,但由于某种原因,此函数的递归方面在我的大脑中并没有很好地流动。

在一个完美的世界中,我希望能够指定要返回多少父节点,但即使只是直接的也会很棒。

    public static AccessibleTreeItem Find(AccessibleTreeItem node, string name)
    {

        if (node == null)
            return null;

        if (node.name == name)
            return node;

        foreach (var child in node.children)
        {
            var found = Find(child, name);
            if (found != null)
                return found;
        }

        return null;
    }

感谢大家花时间看一看。

编辑:因此,例如,我希望能够调用 Find(node, name, parentIndex) 或类似的东西,以传递一个值,该值表示可以找到返回的项目的父级别数在。

编辑 2:为了澄清,我希望能够告诉函数找到一个特定的名称和一个 parentIndex。该函数将定位正在搜索的节点,然后向上遍历“树”指定的层数,最后返回该对象。

所以如果我们调用

    Find(node, "Test", 2)

并且正在搜索的值是:

    node.children[0].children[3].children[2].children[1]

那么该函数应该返回位于以下位置的对象:

    node.children[0].children[3]

【问题讨论】:

  • 您的意思是要限制最大搜索深度?其中“深度”被定义为“递归的级别数”...... Ergo:允许傻瓜调用自己多少次。
  • 不,我想做的是当它在列表中找到正确的对象时,它会遍历“树”指定的级别数,并返回该对象。编辑:因此,如果在 node.children[0].children[0].children[0].children[0] 中找到正确的值,您可以通过一个变量来允许它返回 node.children[0] .children[0].children[0](匹配搜索字符串的对象的父级。)

标签: c# list recursion


【解决方案1】:

啊哈...所以尝试传递 byref 一个名为“ancestorCount”的(正)整数(1 表示父母,2 表示祖父母,3 表示曾祖父,等等)。 ..如果找到返回true(非空)并且祖先计数==0返回这个,否则在返回找到的孩子之前减少祖先计数......

这对你有意义吗?我将在大约 10 分钟内编辑这篇文章,以将其放入伪代码(至少)。

干杯。基思。


编辑:至少提供某种代码。

这不是编译的,更不用说测试了...因此我完全不确定我的条件是否正确...正如 Ben 指出的那样,我可能完全倒退了 ;-)这是一种我通常需要调试一段时间才能正确的事情......但我确实认为“我已经很接近了”,核心思想就在那里......我将把微调留给实施者......你;-)

public static Node Find(Node node, string targetName, ref int ancenstorCount) {
    if ( node == null )
        return null;
    if ( ancenstorCount == 0 ) // we've already found the right level to return
        return node;
    if ( node.name == targetName )
        return node;
    foreach ( Node child in node.Children ) {
        var found = Find(child, targetName);
        if ( found != null ) {
            if ( ancenstorCount == 0 )
                return found;
            --ancenstorCount;
            return node; // return any non-null 
        }
    }
    return null;
}

...但是我可以看到我现在必须实现 Node,只是为了满足我自己对算法正确性的好奇心。叹息。

干杯。基思。


EDIT2:

嗯,这对我有用...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Tree
{
    class Node {
        private List<Node> _kids = new List<Node>();
        public string Name { get; set; }
        public List<Node> Children { get { return _kids; } }
        public void Add(Node child) { _kids.Add(child); }
        public override string ToString() { return Name; }
    }

    class Program
    {
        Node _root;

        static void Main(string[] args) {
            new Program().Run();
            Console.Write("Press any key ...");
            Console.ReadKey();
        }

        Program() {
            _root = GenerateTree();
        }

        static Node GenerateTree()
        {
            // Gen0
            Node root = new Node() { Name = "Great-grandpa Jimmy Joe Jim-Bob John Keith Luke Duke" };
            // Add Gen1 to Gen0
            root.Add(new Node() { Name = "GrandUncle Joe Duke" });
            Node grandDad = new Node() { Name = "Granddad Jimmy Duke" };
            root.Add(grandDad);

            // Add Gen2 to Gen1
            grandDad.Add(new Node() { Name = "Uncle Jim" });
            grandDad.Add(new Node() { Name = "Uncle Bob" });
            Node dad = new Node() { Name = "Dad John" };
            grandDad.Add(dad);

            // Add Gen3 to Gen2
            dad.Add(new Node() { Name = "Brother Luke" });
            dad.Add(new Node() { Name = "Keith" });

            return root;
        }

        void Run() {
            Console.WriteLine("My Great-granddad is: " + Find("Keith", 3));
            Console.WriteLine("My granddad is: " + Find("Keith", 2));
            Console.WriteLine("My dad is: " + Find("Keith", 1));
            Console.WriteLine();
            Console.WriteLine("Brother Luke's Dad is: " + Find("Brother Luke", 1));
            Console.WriteLine("Uncle Bob's dad is: " + Find("Uncle Bob", 1));
            Console.WriteLine("Uncle Jim's granddad is: " + Find("Uncle Jim", 2));
            Console.WriteLine();
            Console.WriteLine("Lunil's mom is: " + Find("Lunil", 1));
            Console.WriteLine();
        }


        string Find(string targetName, int anticedentLevel) {
            Node n = Find(_root, targetName, ref anticedentLevel);
            return n!=null ? n.ToString() : "#NOT_FOUND#";
        }

        private static Node Find(Node node, string targetName, ref int ancenstorCount) {
            if ( node == null )
                return null;
            if ( ancenstorCount == 0 ) // we've already found the right level to return
                return node;
            if ( node.Name == targetName )
                return node;
            foreach ( Node child in node.Children ) {
                var found = Find(child, targetName, ref ancenstorCount);
                if ( found != null ) {
                    if ( ancenstorCount == 0 )
                        return found;
                    --ancenstorCount;
                    return node; // return any non-null 
                }
            }
            return null;
        }

    }
}

输出

我的曾祖父是:曾祖父 Jimmy Joe Jim-Bob John Keith Luke Duke 我的爷爷是:爷爷吉米杜克 我爸爸是:爸爸约翰 卢克弟兄的爸爸是:约翰爸爸 鲍勃叔叔的父亲是:吉米·杜克爷爷 吉姆叔叔的祖父是:曾祖父吉米乔吉姆鲍勃约翰基思卢克杜克 Lunil 的妈妈是:#NOT_FOUND# 按任意键 ...

...尽管在现实世界中,您可能“只是”在每个节点中使用父引用来实现它,仅仅是因为这更简单...并且对其他事情有用。

【讨论】:

  • 好方法,但我认为你的条件倒退了。
  • 从我这里看到的,代码本质上是一样的,但是添加了ancestCount的条件,让它在遍历指定的级别之前不会返回?不幸的是,它不起作用,因为条件 if(ancenstorCount == 0) 中有一个 return node 语句......这是正确的吗?说到递归函数,我有点迷茫,抱歉。
  • Corlettk - 我最终在类上实现了一个父属性,这样我就可以往回走。感谢您的帮助:-)
【解决方案2】:

我不知道“AccessibleTreeItem”是什么——但如果它有一个父属性,那么循环到 node.Parent.Parent 就很容易了。

例如:

public AccessibleTreeItem GetParent(AccessibleTreeItem node, int depth)
{
    if(depth <= 1) // can't go higher than 1
    {
        return node.Parent;
    }
    else
    {
        return GetParent(node.Parent, depth-1);
    }
}

那么从你现有的递归中,你不是返回节点,而是返回 GetParent(node, depth)

但是,如果您没有父参考,那么您需要获得更多创意。我看到 corlettk 正在研究那个例子,听起来他正在做我想做的事情,所以我将把它留给他。

【讨论】:

  • 听取您的建议,我实现了一个父属性并从那里获取了它。感谢您的提醒 - 我试图避免修改 3rd 方类,但这是一种非常简单的方法,而不是尝试以其他方式进行。
  • 哦,太好了,很高兴我能帮上忙。一个节点知道它的父节点是一个非常标准的约定——在不知道这一点的情况下,向上导航是非常困难的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 2018-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多