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

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

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

时间: 2024-08-05 02:08:47

[广度遍历和深度遍历]聊聊算法和设计模式的相关文章

图的广度遍历和深度遍历

/* 图的遍历方法主要有两种:一种是深度优先遍历,一种是广度优先遍历.图的深度优先遍历类同于树的先根遍历,图的广度遍历类同树的层次遍历 一:连通图的深度优先遍历算法 图的深度优先遍历算法是遍历时深度优先的算法,即在图的所有邻接顶点中,每次都在访问当前顶点后,首先访问当前顶点的第一个邻接顶点. 连通图的深度优先遍历递归算法如下: 1.访问顶点v并标记顶点v已访问. 2.查找顶点v的第一个邻接顶点w. 3.若顶点v的邻接顶点w存在,则继续执行,否则算法结束. 4.若顶点w尚未被访问,则深度优先遍历递

第五章 图的遍历(深度遍历,广度遍历,城市地图,最少转机)

深度和广度优先搜索: 单词分解:首先是搜索 深度和广度:是针对图的遍历而言的 图:由顶点和边组成 图的遍历:把图中每一个顶点都访问一次 一: 输入: 5 5(顶点数,边数) 1 2 1 3 1 5 2 4 3 5 输出: 1 2 4 3 5 (按时间戳输出)深度遍历 1 2 3 5 4 (按时间戳输出)广度遍历 1 #include <stdio.h> 2 int map[10][10], book[10], n, m,sum; 3 void dfs(int cur) 4 { 5 int i;

图的深度遍历和广度遍历

概述 图的遍历是指从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次.图的遍历操作和树的遍历操作功能相似.图的遍历是图的一种基本操作,图的其它算法如求解图的连通性问题,拓扑排序,求关键路径等都是建立在遍历算法的基础之上. 由于图结构本身的复杂性,所以图的遍历操作也较复杂,主要表现在以下四个方面:① 在图结构中,没有一个“自然”的首结点,图中任意一个顶点都可作为第一个被访问的结点.② 在非连通图中,从一个顶点出发,只能够访问它所在的连通分量上的所有顶点,因此,还需考虑如何选取下一个出发点以

数据结构-深度遍历和广度遍历(转)

本文转自http://blog.csdn.net/wingofeagle/article/details/13020373 深度遍历: 从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到. 其更适合:目标比较明确,以找到目标为主要目的的情况. 广度遍历: 类似于树中的层序遍历,首先遍历完和某一顶点v相连的所有顶点,然后再遍历和这些顶点相连的顶点,以此类推. 其更适合于:不断扩大遍历范围时找到相对最优解的情况. 具体代码如下:

【数据结构】邻接表的广度与深度遍历

邻接表:数组和链表相结合的方法.图中顶点一般用一个一维数组存储,也可以用单链表存储,每个顶点的邻接点构成一个线性表,一般为单链表. 无向图: 有向图: 代码: #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h" #define OK 1 #define ERROR 0 #defi

Java 实现深度遍历和广度遍历数及其应用

一.深度遍历和广度遍历原理及实现 1.深度优先 英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.对于上面的例子来说深度优先遍历的结果就是:A,B,D,E,I,C,F,G,H.(假设先走子节点的的左侧). 深度优先遍历各个节点,需要使用到堆(Stack)这种数据结构.stack的特点是是先进后出.整个遍历过程如下: 首先将A节点压入堆中,stack(A); 将A节点弹出,同时将A的子节点C,B压入堆中,此

BST和DST简单的matlab程序(图的广度和深度遍历)

图的广度和深度遍历,具体内容教材有 clc;clear all;close all; %初始化邻接压缩表compressTable=[1 2;1 3;1 4;2 4;2 5;3 6;4 6;4 7];max_vertex = max(compressTable(:)); %压缩表中最大值就是邻接矩阵的宽与高graph_matrix = compressTableToMatrix(compressTable);%从邻接压缩表构造图的矩阵表示[x,y] = cylinder(1,max_vertex

邻接表广度深度遍历

#include<iostream> #include<queue> using namespace std; const int MaxVertexNum = 100; bool visited[MaxVertexNum]; int relationNonDir[][2] = {{0,1},{0,2},{1,2},{1,3},{2,6},{2,5},{3,5},{3,4},{4,5}};////无向图 class EdgeNode{ public: int val; int we

一步一步写算法(之二叉树深度遍历)

原文:一步一步写算法(之二叉树深度遍历) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 深度遍历是软件开发中经常遇到的遍历方法.常用的遍历方法主要有下面三种:(1)前序遍历:(2)中序遍历:(3)后序遍历.按照递归的方法,这三种遍历的方法其实都不困难,前序遍历就是根-左-右,中序遍历就是左-根-右,后续遍历就是左-右-根.代码实现起来也不复杂. 1)前序遍历 void preorder_traverse(TREE_NODE* pTree