• [置顶] 如何从树叶层开始建树?


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

          

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

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

    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);
            }
        }   
    }

         

  • 相关阅读:
    Python正则表达式------进阶
    基本数据类型(字符串_数字_列表_元祖_字典_集合)
    python目录
    python------异步IO数据库队列缓存
    saltstack技术入门与实践
    扒一扒JavaScript 预解释
    微信二维码防伪
    web前端页面性能优化小结
    js 中 continue 与 break 熟练使用
    倒计时原生js
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3343482.html
Copyright © 2020-2023  润新知