public UndirectedGraph <T> Add(UndirectedEdge <T> edge)
 {
     _edges.Add(edge);
     foreach (var vertex in edge.Vertexs())
     {
         _vertexs.Add(vertex);
     }
     return(this);
 }
        /// <summary>
        /// 假设G=(V,E)为一无向连通网,其中,V为网中顶点的集合,E为网中边的集合。
        /// 设置两个新的集合U和T,其中,U为G的最小生成树的顶点的集合,T为G的最小生成树的边的集合。
        /// 普里姆算法的思想是:令集合U的初值为U={u1}(假设构造最小生成树时从顶点u1开始),集合T的初值为T={}。
        /// 从所有的顶点u∈U和顶点v∈V-U的带权边中选出具有最小权值的边(u,v),
        /// 将顶点v加入集合U中,将边(u,v)加入集合T中。如此不断地重复直到U=V时,最小生成树构造完毕。
        /// 此时,集合U中存放着最小生成树的所有顶点,集合T中存放着最小生成树的所有边。
        /// </summary>
        /// <returns></returns>
        public List <UndirectedEdge <T> > PrimMinCostSpanTree(T begin_vertex)
        {
            if (!_vertexs.Contains(begin_vertex))
            {
                throw new InvalidOperationException("begin_vertex is not in Graph");
            }

            var ret = new List <UndirectedEdge <T> >();

            var selected_set   = new HashSet <T>();
            var unselected_set = new HashSet <T>();

            selected_set.Add(begin_vertex);
            foreach (var vertex in _vertexs)
            {
                if (!vertex.Equals(begin_vertex))
                {
                    unselected_set.Add(vertex);
                }
            }

            while (unselected_set.Count > 0)
            {
                T vertex_unsel = default(T);
                UndirectedEdge <T> edge_sel = null;
                var min_cost = int.MaxValue;
                foreach (var sel_item in selected_set)
                {
                    foreach (var unsel_item in unselected_set)
                    {
                        foreach (var edge in _edges)
                        {
                            if (edge.ComposedWith(sel_item, unsel_item) && edge.Weight < min_cost)
                            {
                                vertex_unsel = unsel_item;
                                min_cost     = edge.Weight;
                                edge_sel     = edge;
                            }
                        }
                    }
                }

                if (vertex_unsel != null && vertex_unsel.Equals(default(T)))
                {
                    continue;
                }
                selected_set.Add(vertex_unsel);
                unselected_set.Remove(vertex_unsel);
                ret.Add(edge_sel);
            }

            return(ret);
        }
        /// <summary>
        /// 图是否存在环
        /// 1.求出图中所有顶点的度,
        /// 2.删除图中所有度小于等于1的顶点以及与该顶点相关的边,把与这些边相关的顶点的度减一
        /// 3.如果还有度小于等于1的顶点重复步骤2
        /// 4.最后如果还存在未被删除的顶点,则表示有环;否则没有环
        /// </summary>
        /// <returns></returns>
        public bool HasLoop()
        {
            var dic   = _vertexs.ToDictionary(v => v, v => 0); // vertex-degree
            var edges = new HashSet <UndirectedEdge <T> >(_edges);

            foreach (var edge in edges) // init degree of vertexs
            {
                foreach (var v in edge.Vertexs())
                {
                    dic[v]++;
                }
            }

            // delete all vertexs satified degree==0
            var filtered_dic = dic.Where(item => item.Value > 0).ToDictionary(item => item.Key, item => item.Value);

            var to_do_item = GetOneDegreeItem(filtered_dic); // get one vertex which degree == 1

            while (!to_do_item.Equals(default(KeyValuePair <T, int>)))
            {
                UndirectedEdge <T> to_del_edge = null;
                foreach (var edge in edges)
                {
                    if (edge.Contain(to_do_item.Key))
                    {
                        to_del_edge = edge;
                        filtered_dic[edge.GetAdjoinVertex(to_do_item.Key)]--;
                        break;
                    }
                }
                filtered_dic.Remove(to_do_item.Key);
                edges.Remove(to_del_edge);
                to_do_item = GetOneDegreeItem(filtered_dic);
            }

            return(!(filtered_dic.Count == 0 ||
                     filtered_dic.All(item => item.Value == 0)));
        }