【问题标题】:Recursive function issue递归函数问题
【发布时间】:2015-01-27 02:51:49
【问题描述】:

我正在使用安装位置的树形结构:每个位置都可能包含子 InstallationPlace,这些也可以包含子 InstallationPlace,依此类推。我有以下功能:

public JsonResult GetInstPlacesTree()
{
    InstallationPlaceModel ipm = new InstallationPlaceModel();
    var dataContext = ipm.getRootInstallationPlaces();

    var instPlaces = from ip in dataContext.installationPlaces
                    select new
                    {
                        id = ip.installationPlace.id,
                        Name = ip.installationPlace.mediumDescription,
                    };

    return Json(instPlaces, JsonRequestBehavior.AllowGet);
}

这个函数只返回树的根层。

我有两种工作方法:

  • 一个返回根安装位置;
  • 另一个返回给定安装位置的子代;

它们都返回 IEnumerable 变量。

getRootInstallationPlaces();
getChildInstallationPlaces(id);

我怎样才能调用所有的安装位置和相应的孩子?

我已经尝试过GetInstPlacesTree() 函数的替代方法:

private IEnumerable<TreeViewItemModel> GetDefaultInlineData()
{
    InstallationPlaceModel ipm = new InstallationPlaceModel();
    List<TreeViewItemModel> fullTree = new List<TreeViewItemModel>();
    var gipo = ipm.getChildInstallationPlaces(currentInstallationPlace.InstallationPlaceId);
    List<TreeViewItemModel> childTree = new List<TreeViewItemModel>();
    if (gipo.installationPlaces.Count() > 0)
    {
        foreach (wsInstallationPlace.installationPlaceOutput child in gipo.installationPlaces)
        {
            TreeViewItemModel childTreeItem = new TreeViewItemModel
            {
                Text = child.installationPlace.mediumDescription,
                Id = child.installationPlace.id
            };
            childTree.Add(childTreeItem);
        }
    }
    TreeViewItemModel fatherTreeItem = new TreeViewItemModel
    {
        Text = currentInstallationPlace.InstallationPlaceMediumDescription,
        Id = currentInstallationPlace.InstallationPlaceId,
        Items = childTree
    };
    fullTree.Add(fatherTreeItem);
    return fullTree;
}

有什么帮助吗?

【问题讨论】:

  • 在理解递归之前,必须先理解递归。

标签: c# function recursion


【解决方案1】:

您可以使用以下方法在不递归的情况下解决此问题。我用某种伪代码编写了它,所以你会知道我建议完成什么,我没有使用你的确切函数名称、结构和类......

queue = new List<>();
queue.Add(initialInstallation);
retVal = new List<>();

while (queue.Count > 0) {
    retVal.Add(queue[0].GetData());
    queue.Add(queue[0].GetChildren());
    queue.Remove(0);
}

return retVal;

【讨论】:

    【解决方案2】:

    要使其递归,您必须认为子位置同时是它们自己子节点的根,然后您可以为它们调用相同的函数。

    private IEnumerable<TreeViewItemModel> RecursivePlaces(InstallationPlace root){
         var output = new List<TreeViewItemModel>();
         output.add(new TreeViewItemModel
            {
                Text = root.installationPlace.mediumDescription,
                Id = root.installationPlace.id
            });         
    
         foreach(var child in root.installationPlaces)
           output.AddRange(RecursivePlaces(child));
    
         return output;
    }
    
    //Initial call
    RecursivePlaces(ipm.getRootInstallationPlace());
    

    【讨论】:

    • 感谢您的回答。我理解这个概念并且知道每个地方都将成为其子节点的根,我只想将其调整为我当前的代码。不幸的是,你的回答是理论上的,它不能解决我的具体问题。不能这样申请
    • 您能否详细解释一下您的功能的目标是什么?是获取TreeViewItemModel的列表吗?
    • 是的,我想得到一个这种格式的树,你可以在我的后一个函数中看到
    • 问题出在foreach循环上,因为安装位置没有安装位置(foreach(var child in root.installationPlaces))。获得子安装位置的唯一方法是通过getChildInstallationPlaces(id) 方法。这不容易,我已经挣扎了一段时间了
    【解决方案3】:

    我认为以下内容应该可以满足您的需求。本质上,它使您的初始方法几乎保持原样,但它通过递归调用填充每个顶级的子 Items

    递归调用获取子级并将每个子级添加到要返回的List&lt;TreeViewItemModel&gt;,但它们的子级又由对递归函数的调用填充。当没有孩子时,递归将结束:

    public JsonResult GetInstPlacesTree()
    {
        InstallationPlaceModel ipm = new InstallationPlaceModel();
        var dataContext = ipm.getRootInstallationPlaces();
    
        var instPlaces = from ip in dataContext.installationPlaces
                            select new TreeViewItemModel 
                            {
                                id = ip.installationPlace.id,
                                Name = ip.installationPlace.mediumDescription,
                                Items = getChildInstallationPlacesRecursive(ip.installationPlace.id, ipm)
                            };
    
        return Json(instPlaces, JsonRequestBehavior.AllowGet);
    }
    
    public List<TreeViewItemModel> getChildInstallationPlacesRecursive(int id, InstallationPlaceModel ipm)
    {
        List<TreeViewItemModel> children = new List<TreeViewItemModel>();
    
        var gipo = ipm.getChildInstallationPlaces(id);
    
        foreach (wsInstallationPlace.installationPlaceOutput child in gipo.installationPlaces)
        {
            children.Add(new TreeViewItemModel
            {
                Text = child.installationPlace.mediumDescription,
                Id = child.installationPlace.id,
                Items = getChildInstallationPlacesRecursive(child.installationPlace.id, ipm)
            });
        }
    
        return children;
    }
    

    【讨论】:

    • 感谢您的回答。结果是一棵没有孩子的树。有 3 个根节点,但其子节点不存在
    • 如果在var gipo = ipm.getChildInstallationPlaces(id); 上设置断点会发生什么 - 有任何结果吗?我唯一能想到的是我应该通过将ipm 传递给getChildInstallationPlacesRecursive 来重新使用它。除此之外,我认为逻辑是正确的。我会更新代码。
    • gipo变量包含ID作为参数传递的安装地点的所有孩子。这些方法非常有效。我会试试你更新的代码,谢谢
    • 我不得不对其进行调整,以便符合我的利益,但您的逻辑确实是正确的,并引导我找到了解决方案。谢谢! +1,赏金和正确答案!顺便说一句,我的问题不值得投票吗? ;)
    • 我很高兴能帮助@chiapa。碰巧的是,我认为您的问题值得投票。 +1。干杯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    • 2017-10-18
    • 2020-09-09
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 2021-01-08
    相关资源
    最近更新 更多