/// <summary>
        /// 判断节点是否是指定节点的后代节点
        /// </summary>
        /// <typeparam name="T">节点数据类型</typeparam>
        /// <param name="node">待判断的节点</param>
        /// <param name="target">目标节点</param>
        /// <returns>判断结果</returns>
        public static bool IsDescendantOf <T>(this IHierarchical <T> node, IHierarchical <T> target)
        {
            if (node.Root != target.Root)
            {
                throw new InvalidOperationException($"{nameof(node)} and {nameof(target)} are not at same tree.");
            }

            return(target.IsAncestorOf(node));
        }
        /// <summary>
        /// 获取从指定节点到当前节点的路径
        /// </summary>
        /// <typeparam name="T">节点数据类型</typeparam>
        /// <param name="node">当前节点(终点)</param>
        /// <param name="from">目标节点(起点)</param>
        /// <returns>按从目标节点到当前节点顺序经过的节点集合</returns>
        public static IEnumerable <IHierarchical <T> > GetPathFromNode <T>(this IHierarchical <T> node,
                                                                           IHierarchical <T> from)
        {
            if (node.Root != from.Root)
            {
                throw new InvalidOperationException($"{nameof(node)} and {nameof(from)} are not at same tree.");
            }

            yield return(from); //起点必然是需要的

            if (node == from)
            {
                yield break;               //如果终点就是起点,那么可以直接结束路径查找了
            }
            //只有终点和起点不存在双亲孩子关系时才需要执行内部代码,否则直接返回终点即可
            if (!(node.Parent == from || node.Children.Any(n => n == from)))
            {
                var nearestCommonAncestor = node.GetNearestCommonAncestor(from);

                //如果起点不是终点的祖先,需要先返回从起点的双亲到最近公共祖先
                //(不包括最近公共祖先。最近公共祖先可能就是终点,返回的话会导致终点被返回两次。终点会在方法末尾统一返回)的路径
                if (!from.IsAncestorOf(node))
                {
                    foreach (var ancestor in from.Ancestors)
                    {
                        if (ancestor != nearestCommonAncestor)
                        {
                            yield return(ancestor);
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                //如果最近公共祖先不是终点,返回从最近公共祖先到终点(不包括终点,原因不再赘述)的路径
                if (nearestCommonAncestor != node)
                {
                    var ancestorsOfNode = node.Ancestors.ToArray();
                    for (int i = Array.IndexOf(ancestorsOfNode, nearestCommonAncestor); i >= 0; i--)
                    {
                        yield return(ancestorsOfNode[i]);
                    }
                }
            }

            yield return(node); //最后返回终点
        }
        /// <summary>
        /// 获取节点与指定节点的最近公共祖先节点
        /// </summary>
        /// <typeparam name="T">节点数据类型</typeparam>
        /// <param name="node">待查找的节点</param>
        /// <param name="target">目标节点</param>
        /// <returns>最近的公共祖先节点</returns>
        public static IHierarchical <T> GetNearestCommonAncestor <T>(this IHierarchical <T> node, IHierarchical <T> target)
        {
            if (node.Root != target.Root)
            {
                throw new InvalidOperationException($"{nameof(node)} and {nameof(target)} are not at same tree.");
            }

            if (node.IsAncestorOf(target))
            {
                return(node);
            }
            if (target.IsAncestorOf(node))
            {
                return(target);
            }

            return(node.Ancestors.Intersect(target.Ancestors).OrderByDescending(no => no.Level).First());
        }
示例#4
0
        /// <summary>
        /// 获取从指定节点到当前节点的路径
        /// </summary>
        /// <typeparam name="T">节点数据类型</typeparam>
        /// <param name="node">当前节点(终点)</param>
        /// <param name="from">目标节点(起点)</param>
        /// <returns>按从目标节点到当前节点顺序经过的节点集合</returns>
        public static IEnumerable <IHierarchical <T> > GetPathFromNode <T>(this IHierarchical <T> node,
                                                                           IHierarchical <T> from)
        {
            if (node.Root != from.Root)
            {
                throw new InvalidOperationException($"{nameof(node)} and {nameof(from)} are not at same tree.");
            }

            yield return(from);

            if (node == from)
            {
                yield break;
            }

            if (node.IsAncestorOf(from))
            {
                foreach (var ancestor in from.Ancestors)
                {
                    yield return(ancestor);

                    if (ancestor == node)
                    {
                        yield break;
                    }
                }
            }

            var ancestorsOfNode = node.Ancestors.ToArray();

            if (node.IsDescendantOf(from))
            {
                for (int i = Array.IndexOf(ancestorsOfNode, from) - 1; i >= 0; i--)
                {
                    yield return(ancestorsOfNode[i]);
                }

                yield return(node);

                yield break;
            }

            var keyNode = ancestorsOfNode.Intersect(from.Ancestors).OrderByDescending(no => no.Level).First();

            foreach (var ancestor in from.Ancestors)
            {
                yield return(ancestor);

                if (ancestor == keyNode)
                {
                    break;
                }
            }

            for (int i = Array.IndexOf(ancestorsOfNode, keyNode) - 1; i >= 0; i--)
            {
                yield return(ancestorsOfNode[i]);
            }

            yield return(node);
        }