如何从树叶层开始建树?

     在开发软件的过程中,遇到一个树形结构的问题,如下图:

      

     由于树形结构太大,只显示部分叶节点,并且报价是叶节点的数量和报价的成积。

 问题经分析很显然:变成了如下两个问题:

1从树的根节点开始建树就是一个简单的递归,但现在的问题是从树的叶节点开始如何建树,涉及到一个如何合并子节点的问题。

2如何根据叶节点的数量和报价计算各级父节点的报价?


1如何从树的叶节点开始如何建树?

 有一种思路,就是按照正常思路建好后,然后把没有子节点的删掉,很麻烦。

于是想着能不能通过叶节点的递归一层一层向上,最终完成树的创建。

最总实现代码如下:

 /// <summary>
    /// 返回需要的树
    /// </summary>
    /// <param name="listAllNodes">所有的节点信息</param>
    /// <param name="dicNode">键为父节点编号,值为父节点对应的子节点  ,初始为需要显示的叶节点</param>
    /// <returns></returns>
    public static List<TreeNode> GeTree(List<TreeNode> listAllNodes, Dictionary<int, List<TreeNode>> dicNode)
    {
        int rootNodeId = -1;//虚拟的根节点编号
        while (!dicNode.ContainsKey(rootNodeId)) //如果没有到根节点继续
        {
            dicNode = GetOneLevelNodes(listAllNodes, dicNode);
        }
        return dicNode[rootNodeId];
    }
    /// <summary>
    /// 返回某一层的所有节点,包含子节点
    /// </summary>
    /// <param name="listAllNodes">所有的节点信息</param>
    /// <param name="dicNode">键为父节点编号,值为父节点对应的子节点</param>
    /// <returns></returns>
    private static Dictionary<int, List<TreeNode>> GetOneLevelNodes(List<TreeNode> listAllNodes, Dictionary<int, List<TreeNode>> dicNode)
    {
        int rootNodeId = -1; //虚拟的根节点编号      
        List<int> ParentsIdList = new List<int>();
        ParentsIdList.AddRange(dicNode.Keys);//这次需要添加的节点编号
        Dictionary<int, List<TreeNode>> dicNode2 = new Dictionary<int, List<TreeNode>>();//键为父节点编号,值为父节点对应的子节点
        for (int i = listAllNodes.Count - 1; i >= 0; i--)
        {
            TreeNode item = listAllNodes[i];
            if (ParentsIdList.Contains(item.ID))
            {               
                int parentId = rootNodeId;//默认为顶级节点
                if (item.ParentID.HasValue)//如果存在父节点
                {
                    parentId = item.ParentID.Value;
                }
                List<TreeNode> children = dicNode[item.ID];//获取此节点对应的父节点
                item.children = children;//添加子节点
                AddOneNode(parentId, dicNode2, item);//添加节点到字典中
                listAllNodes.RemoveAt(i);//移除已经处理的节点
            }
        }
        return dicNode2;
    }
    /// <summary>
    /// 合并具有相同父节点的兄弟节点
    /// </summary>
    /// <param name="parentId">需要处理的节点的父节点</param>
    /// <param name="dicNode">此层对应的节点字典</param>
    /// <param name="node">需要处理的节点</param>
    private static void AddOneNode(int parentId, Dictionary<int, List<TreeNode>> dicNode, TreeNode node)
    {
        if (dicNode.ContainsKey(parentId))//如果有
        {
            dicNode[parentId].Add(node);//如果具有相同的父节点,则添加到相应的兄弟节点列表中
        }
        else//如果没有
        {
            List<TreeNode> listChild = new List<TreeNode>();
            listChild.Add(node);//兄弟节点列表
            dicNode.Add(parentId, listChild);
        }
    }   

2如何根据叶节点的数量和报价计算各级父节点的报价?

     由于每一个节点的报价都是通过它的子节点的报价计算出来的,似乎在树建成后,还需要遍历一次计算报价?如何写代码?似乎还真不好处理?

     想不到最总却是通过属性解决的。

核心代码如下:

  

 private double m_Price = 0;//默认为0,
    public double Price
    {
        get
        {
            if (m_Price == 0)//如果是默认值,则调用方法计算
            {
                m_Price = GetPrice(); 
            }
            return m_Price;
        }
        set { m_Price = value; }
    }
    /// <summary>
    /// 通过子节点计算此节点的报价
    /// </summary>
    /// <returns></returns>
    private double GetPrice()
    {
        if (m_Price > 0)//已经计算过,直接返回
        {
            return m_Price;
        }

        double PriceTemp = 0;
        if (children != null && children.Count > 0)
        {
            foreach (TreeNode node in children)// 通过子节点计算此节点的报价
            {
                if (node.Count.HasValue)
                {
                    PriceTemp += node.Count.Value * node.Price;
                }
                else
                {
                    PriceTemp += node.Price;
                }
            }
        }      
        return PriceTemp;
    }

  完整代码:

public class TreeNode
{
    private int m_ID;
    public int ID
    {
        get { return ID; }
        set { ID = value; }
    }
    private int? m_ParentID;
    public int? ParentID
    {
        get { return m_ParentID; }
        set { m_ParentID = value; }
    }
    private int? m_Count;
    public int? Count
    {
        get { return m_Count; }
        set { m_Count = value; }
    }
    private string m_PL_Code;
    public string PL_Code
    {
        get { return m_PL_Code; }
        set { m_PL_Code = value; }
    }  
    private string m_Name;
    public string Name
    {
        get { return m_Name; }
        set { m_Name = value; }
    }
    private double m_Price = 0;//默认为0,
    public double Price
    {
        get
        {
            if (m_Price == 0)//如果是默认值,则调用方法计算
            {
                m_Price = GetPrice(); 
            }
            return m_Price;
        }
        set { m_Price = value; }
    }
    /// <summary>
    /// 通过子节点计算此节点的报价
    /// </summary>
    /// <returns></returns>
    private double GetPrice()
    {
        if (m_Price > 0)//已经计算过,直接返回
        {
            return m_Price;
        }

        double PriceTemp = 0;
        if (children != null && children.Count > 0)
        {
            foreach (TreeNode node in children)// 通过子节点计算此节点的报价
            {
                if (node.Count.HasValue)
                {
                    PriceTemp += node.Count.Value * node.Price;
                }
                else
                {
                    PriceTemp += node.Price;
                }
            }
        }      
        return PriceTemp;
    }
    private List<TreeNode> m_children;
    public List<TreeNode> children
    {
        get { return m_children; }
        set { m_children = value; }
    }
    /// <summary>
    /// 返回需要的树
    /// </summary>
    /// <param name="listAllNodes">所有的节点信息</param>
    /// <param name="dicNode">键为父节点编号,值为父节点对应的子节点  ,初始为需要显示的叶节点</param>
    /// <returns></returns>
    public static List<TreeNode> GeTree(List<TreeNode> listAllNodes, Dictionary<int, List<TreeNode>> dicNode)
    {
        int rootNodeId = -1;//虚拟的根节点编号
        while (!dicNode.ContainsKey(rootNodeId)) //如果没有到根节点继续
        {
            dicNode = GetOneLevelNodes(listAllNodes, dicNode);
        }
        return dicNode[rootNodeId];
    }
    /// <summary>
    /// 返回某一层的所有节点,包含子节点
    /// </summary>
    /// <param name="listAllNodes">所有的节点信息</param>
    /// <param name="dicNode">键为父节点编号,值为父节点对应的子节点</param>
    /// <returns></returns>
    private static Dictionary<int, List<TreeNode>> GetOneLevelNodes(List<TreeNode> listAllNodes, Dictionary<int, List<TreeNode>> dicNode)
    {
        int rootNodeId = -1; //虚拟的根节点编号      
        List<int> ParentsIdList = new List<int>();
        ParentsIdList.AddRange(dicNode.Keys);//这次需要添加的节点编号
        Dictionary<int, List<TreeNode>> dicNode2 = new Dictionary<int, List<TreeNode>>();//键为父节点编号,值为父节点对应的子节点
        for (int i = listAllNodes.Count - 1; i >= 0; i--)
        {
            TreeNode item = listAllNodes[i];
            if (ParentsIdList.Contains(item.ID))
            {               
                int parentId = rootNodeId;//默认为顶级节点
                if (item.ParentID.HasValue)//如果存在父节点
                {
                    parentId = item.ParentID.Value;
                }
                List<TreeNode> children = dicNode[item.ID];//获取此节点对应的子节点
                item.children = children;//添加子节点
                AddOneNode(parentId, dicNode2, item);//添加节点到字典中
                listAllNodes.RemoveAt(i);//移除已经处理的节点
            }
        }
        return dicNode2;
    }
    /// <summary>
    /// 合并具有相同父节点的兄弟节点
    /// </summary>
    /// <param name="parentId">需要处理的节点的父节点</param>
    /// <param name="dicNode">此层对应的节点字典</param>
    /// <param name="node">需要处理的节点</param>
    private static void AddOneNode(int parentId, Dictionary<int, List<TreeNode>> dicNode, TreeNode node)
    {
        if (dicNode.ContainsKey(parentId))//如果有
        {
            dicNode[parentId].Add(node);//如果具有相同的父节点,则添加到相应的兄弟节点列表中
        }
        else//如果没有
        {
            List<TreeNode> listChild = new List<TreeNode>();
            listChild.Add(node);//兄弟节点列表
            dicNode.Add(parentId, listChild);
        }
    }   
}

     

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值