如何从树叶层开始建树二?

第一篇如何从树叶层开始建树?算法其实是有问题的,它要求完整的树形结构结构(也就是所有节点都显示的树)的树叶节点在同一高度,否则就会有问题。

例如如下的树形就会出问题。

如果出现这种情况如何实现第一篇中业务逻辑呢?

前提条件是知道所有的树节点,如何只显示满足一定条件的叶节点组成的树呢?

此处为了简化,改为显示树叶节点标示为奇数的叶节点组成的树。

前提条件:

1知道树的所有节点

2知道满足条件的树叶节点(也就是树叶节点标示为奇数的叶节点)

如何建立如下的树形结构:

对于上图的树最总显示应该为:

显然,使用第一篇文章的算法有问题。

如果使用从树叶节点开始建树,就会涉及如何合并同一个父节点的子节点问题?

思考了很长时间,竟然发现,这种思路很难实现,如果实现,算法也非常复杂。

因为非常熟悉从根节点开始建树的算法,如果能获取到最终显示的所有节点(也就是去掉不需要的节点集合),那么就可以使用从根节点开始建树的算法。

因此思路就是

1获取所有需要的节点(去掉不需要的节点)

2从根节点开始建树


最终代码:

  /// <summary>
    /// 返回需要的树
    /// </summary>
    /// <param name="listAllNodes">树的所有节点,包含不需要显示的节点</param>
    /// <param name="dicNodes">键为节点编号,值为节点,初始为需要显示的叶节点</param>
    /// <returns></returns>
    public static List<TreeNode> GeTree(List<TreeNode> listAllNodes, Dictionary<int, TreeNode> dicNodes)
    {
        Dictionary<int, TreeNode> listAllRootNodes = new Dictionary<int, TreeNode>();//保存需要的所有节点
        List<TreeNode> leafNodes = new List<TreeNode>();
        leafNodes.AddRange(dicNodes.Values);
        foreach (TreeNode node in leafNodes)//遍历叶节点,
         {
             GetAllNodes(listAllNodes, node.ParentID.Value, ref listAllRootNodes, ref  dicNodes);
         }
         List<TreeNode> allNode = new List<TreeNode>();
         allNode.AddRange(dicNodes.Values);//所有需要显示的节点,树的根节点没有包含在其中
         foreach (TreeNode node in listAllRootNodes.Values)//遍历根节点
        {
            List<TreeNode> childnodes = GetAllChildNodes(allNode, node);
            node.children = childnodes;    
        }
         List<TreeNode> AllRootNodes = new List<TreeNode>();
         AllRootNodes.AddRange(listAllRootNodes.Values);//所有需要显示的节点,树的根节点没有包含在其中
         return AllRootNodes;
    }
    /// <summary>
    ///  递归,得到所有需要的的根节点,和所有需要其他的节点
    /// </summary>
    /// <param name="listAllTreeNodes">树的所有节点,包含不需要的节点</param>
    /// <param name="nodeId"></param>
    /// <param name="listAllRootNodes">保存树的根节点</param>
    /// <param name="dicNode">键为节点编号,值为节点,包含所有需要的节点</param>
    private static void GetAllNodes(List<TreeNode> listAllTreeNodes, int nodeId, ref Dictionary<int, TreeNode> listAllRootNodes, ref  Dictionary<int, TreeNode> dicNode)
    {
        foreach (TreeNode item in listAllTreeNodes)
        {
            if (item.ID == nodeId)
            {
                if (item.ParentID.HasValue)//存在父节点
                {
                    int parentId = item.ParentID.Value;
                    if (!dicNode.ContainsKey(nodeId))//此节点没有添加
                    {
                        dicNode.Add(nodeId, item);                       
                    }
                    if (!dicNode.ContainsKey(parentId))//此节点没有添加
                    {
                        GetAllNodes(listAllTreeNodes, parentId, ref listAllRootNodes, ref  dicNode);
                    }
                }
                else//不存在父节点,也就是根节点
                {
                    if (!listAllRootNodes.ContainsKey(nodeId))//此节点没有添加
                    {
                        listAllRootNodes.Add(nodeId,item); //把此节点添加入根节点的集合
                    }
                 
                }

            }
        }
    }
    /// <summary>
    /// 返回某个节点的子节点
    /// </summary>
    /// <param name="listAllTreeNodes">所有需要显示的节点</param>
    /// <param name="parentNode">父节点</param>
    private static List<TreeNode> GetAllChildNodes(List<TreeNode> listAllTreeNodes, TreeNode parentNode)
    {
        List<TreeNode> ChildNodes = new List<TreeNode>();
        foreach (TreeNode item in listAllTreeNodes)
        {
            if (item.ParentID.HasValue)
            {
                int parentId = item.ParentID.Value;
                if (parentId == parentNode.ID)
                {
                    List<TreeNode> ChildNodes2 = GetAllChildNodes(listAllTreeNodes, item);
                    item.children = ChildNodes2;
                    ChildNodes.Add(item);                  
                }             

            }
        }
        return ChildNodes;
    }

可以看到递归了很多次,性能不是很好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值