• [广度遍历和深度遍历]聊聊算法和设计模式


    晚上无聊写了个二叉树(图)的广度和深度遍历算法,算法本身很简单,但是如何做到通用呢,一下代码是我的设计,请大家帮忙看看有什么问题,我自己感觉有问题就是不知道具体什么问题

        public interface IGraph<TVertex>
        {
            IEnumerable<IEdge<TVertex>> Edges { get; }
        }
        public interface IEdge<TVertex>
        {
            TVertex From { get; set; }
            TVertex To { get; set; }
        }
        public interface INode
        {
            IEnumerable<TNode> GetNextNodes<TNode>() where TNode : INode;
        }
        public class Edge<TVertex> : IEdge<TVertex>
        {
            public TVertex From { get; set; }
            public TVertex To { get; set; }
        }
        public static class NodeVisitor
        {
            public static void BreadthVisit<TNode>(TNode rootNode, Action<TNode> visitAction)
               where TNode : INode
            {
                BreadthVisit(rootNode, n => n.GetNextNodes<TNode>(), visitAction);
            }
    
            public static void BreadthVisit<TNode>(TNode rootNode, Func<TNode,IEnumerable<TNode>> nextNodeSelector, Action<TNode> visitAction)
            {
                var nodeQueue = new Queue<TNode>();
                nodeQueue.Enqueue(rootNode);
                while (nodeQueue.Any())
                {
                    var currentNode = nodeQueue.Dequeue();
                    if (visitAction != null)
                    {
                        visitAction(currentNode);
                    }
                    foreach (var nextNode in nextNodeSelector(currentNode))
                    {
                        nodeQueue.Enqueue(nextNode);
                    }
                }
            }
    
            public static void DepthVisit<TNode>(TNode rootNode, Func<TNode, IEnumerable<TNode>> nextNodeSelector, Action<TNode> visitAction)
            {
                var nodeStack = new Stack<TNode>();
                nodeStack.Push(rootNode);
                while (nodeStack.Any())
                {
                    var currentNode = nodeStack.Pop();
                    if (visitAction != null)
                    {
                        visitAction(currentNode);
                    }
                    foreach (var nextNode in nextNodeSeletor(currentNode))
                    {
                        nodeStack.Push(nextNode);
                    }
                }
            }
    
            public static void DepthVisit<TNode>(TNode rootNode, Action<TNode> visitAction)
               where TNode : INode
            {
                DepthVisit(rootNode, n => n.GetNextNodes<TNode>(), visitAction);
            }
        }
        public class GraphVisitor<TVertex> 
        {
            private IGraph<TVertex> _graph;
    
            public GraphVisitor(IGraph<TVertex> graph)
            {
                _graph = graph;
            }
    
            public TVertex GetRoot()
            {
                var vertexs = _graph.Edges.Select(t => t.From).Concat(_graph.Edges.Select(t => t.To));
                var toVertexs = _graph.Edges.Select(t => t.To);
                return vertexs.FirstOrDefault(t => toVertexs.All(v => !v.Equals(t)));
            }
    
            public IEnumerable<TVertex> GetNextVertexs(TVertex current)
            {
                return _graph.Edges.Where(t => t.From.Equals(current)).Select(t => t.To);
            }
    
            public void BreadthVisit(Action<TVertex> visitAction, TVertex startVertex)
            {
                NodeVisitor.BreadthVisit(startVertex, t => GetNextVertexs(t), visitAction);
            }
    
            public void BreadthVisit(Action<TVertex> visitAction)
            {
                NodeVisitor.BreadthVisit(GetRoot(), t => GetNextVertexs(t), visitAction);
            }
    
            public void DepthVisit(Action<TVertex> visitAction, TVertex startVertex)
            {
                NodeVisitor.DepthVisit(startVertex, t => GetNextVertexs(t), visitAction);
            }
    
            public void DepthVisit(Action<TVertex> visitAction)
            {
                NodeVisitor.DepthVisit(GetRoot(), t => GetNextVertexs(t), visitAction);
            }
    
            private class GraphNode : INode
            {
                private IList<INode> nodes = new List<INode>();
    
                public string Id { get; set; }
    
                public void AddNext(INode node)
                {
                    nodes.Add(node);
                }
    
                public IEnumerable<TNode> GetNextNodes<TNode>() where TNode : INode
                {
                    return nodes.Cast<TNode>();
                }
            }
        }

     单元测试代码:

        [TestClass]
        public class BreadthVisitorTest
        {
            [TestMethod]
            public void TestVisit()
            {
                var node1 = new TestNode() { Id = "1" };
    
                var node1_1 = new TestNode() { Id = "1_1" };
                var node1_2 = new TestNode() { Id = "1_2" };
    
                var node1_1_1 = new TestNode() { Id = "1_1_1" };
                var node1_1_2 = new TestNode() { Id = "1_1_2" };
                var node1_1_3 = new TestNode() { Id = "1_1_3" };
    
                var node1_2_1 = new TestNode() { Id = "1_2_1" };
                var node1_2_2 = new TestNode() { Id = "1_2_2" };
    
                node1.AddNext(node1_1);
                node1.AddNext(node1_2);
    
                node1_1.AddNext(node1_1_1);
                node1_1.AddNext(node1_1_2);
                node1_1.AddNext(node1_1_3);
    
                node1_2.AddNext(node1_2_1);
                node1_2.AddNext(node1_2_2);
                var expected = "1.1_1.1_2.1_1_1.1_1_2.1_1_3.1_2_1.1_2_2";
                var actual = "";
                NodeVisitor.BreadthVisit(node1, n => {
                    actual += n.Id + ".";
                });
    
                Assert.AreEqual(expected, actual.Trim('.'));
    
                expected = "1.1_1.1_1_1.1_1_2.1_1_3.1_2.1_2_1.1_2_2";
                actual = "";
                NodeVisitor.DepthVisit(node1, n => {
                    actual += n.Id + ".";
                });
            }
    
            [TestMethod]
            public void TestGraphVisit()
            {
                var graph = new Graph();
                var graphVisitor = new GraphVisitor<int>(graph);
    
                graph.AddEdge(1, 2);
                graph.AddEdge(1, 3);
    
                graph.AddEdge(2, 4);
                graph.AddEdge(2, 5);
    
                graph.AddEdge(3, 6);
    
                var expected = "123456";
                var actual = "";
    
                graphVisitor.BreadthVisit(a => { actual += a.ToString(); });
    
                Assert.AreEqual(expected, actual);
    
                expected = "124536";
                actual = "";
                graphVisitor.DepthVisit(a => { actual += a.ToString(); });
    
            }
        }
    
        public class TestNode : INode
        {
            private IList<INode> nodes = new List<INode>();
    
            public string Id { get; set; }
    
            public void AddNext(INode node)
            {
                nodes.Add(node);
            }
    
            public IEnumerable<TNode> GetNextNodes<TNode>() where TNode : INode
            {
                return nodes.Cast<TNode>();
            }
        }
    
        public class Graph : IGraph<int>
        {
            private IList<IEdge<int>> _edges = new List<IEdge<int>>();
            public IEnumerable<IEdge<int>> Edges
            {
                get
                {
                    return _edges;
                }
            }
    
            public void AddEdge(int from, int to)
            {
                _edges.Add(new Edge<int>() { From = from, To = to });
            }
        }
    View Code
  • 相关阅读:
    mysql参数优化
    看见的一个mysql面试题
    面向对象的继承
    面向对象的权限修饰符
    php实现无限极分类
    php的冒泡排序
    frame框架的跳转
    thinkphp中open路径问题
    mysql触发器
    mysql事务
  • 原文地址:https://www.cnblogs.com/liubiaocai/p/Breadth-Depth-Algorithm.html
Copyright © 2020-2023  润新知