【Data Structure】Graph Traversal and Minimum Spanning Tree

In the previous blog , I talked about the basic concepts of graphs and how to store them. Let 's learn about graph traversal and minimum spanning tree problems.

traversal of graph

Breadth First Search (BFS)

For an example:
write picture description here
  Suppose we all start traversing from vertex A, the left side is a directed graph, and its breadth-first search result is: ADBEC; the right side is an undirected graph, and its breadth-first search result is: AEDBC.
Breadth-first search is similar to tree-level order traversal. When implemented, it needs to be implemented with the help of queues.

//我们使用一个数组来区别一个顶点是否已经遍历过,遍历过的设置为true。
    void BFS(const V& v)
    {
        queue<int> q;
        vector<bool> visited(_v.size(), false);//遍历过的置为true,默认为false
        size_t index = GetIndex(v);
        q.push(index);
        _BFS(q, visited);
        for (size_t i = 0; i < _v.size(); i++)//为什么要这么写?
            //假如我们的图中的一个顶点与其他的顶点没有关系,即两个顶点之间没有边,
            //那么如果我们不这么写,就会漏掉这个顶点。
            //因此,我们的处理方法是 先遍历一次,然后在看哪个点没有遍历,
            //如果有点没遍历,那么将该点push到队列中遍历。
        {
            if (visited[i] == false)
            {
                q.push(i);
                _BFS(q, visited);
            }
        }
        cout << endl;
    }

    void _BFS(queue<int>& q, vector<bool>& visited)
    {
        while (!q.empty())
        {
            size_t index = q.front();
            q.pop();
            if (visited[index] == true)
                continue;
            cout << _v[index] << " ";
            visited[index] = true;
            pNode pCur = _linkEdges[index];
            while (pCur)
            {
                if (visited[pCur->_dst] == false)
                    q.push(pCur->_dst);
                pCur = pCur->_pNext;
            }
        }
    }

Take the two graphs in the above figure as an example: in the
write picture description here
  above figure, the left side is a directed graph, the red numbers indicate the order of traversal, and the arrows indicate how to go during traversal, so its depth-first search results are: ADEBC, right The side is an undirected graph, and the result of the depth-first search is: ADECB. It can be found that the result of traversal is not unique, it is related to the storage of edges in your graph.

    void DFS(const V& v)
    {
        size_t index = GetIndex(v);
        vector<bool> visited(_v.size(), false);
        _DFS(index, visited);

        for (size_t i = 0; i < _v.size(); i++)
        {
            if (visited[i] == false)
                _DFS(i, visited);
        }
        cout << endl;
    }

    void _DFS(int index, vector<bool>& visited)
    {
        cout << _v[index] << " ";
        visited[index] = true;
        pNode pCur = _linkEdges[index];
        while (pCur)
        {
            if (visited[pCur->_dst] == false)
                _DFS(pCur->_dst, visited);
            pCur = pCur->_pNext;
        }
    }

minimum spanning tree

Each spanning tree in the connected graph is a maximal acyclic subgraph of the original graph, that is, if any edge is deleted from it, the spanning tree does not need to be connected again; on the contrary, if there is an edge in it, it will be form a loop.
If a connected graph consists of n vertices, the spanning tree must have n vertices and n-1 edges. The minimum spanning tree is the spanning tree with the smallest sum of the weights of the edges. Therefore, the following three points need to be observed to form the minimum spanning tree:

  1. Only edges in the graph can be used to form a minimum spanning tree
  2. Only n vertices in a graph can be linked using exactly n-1 edges
  3. The selected n-1 edges are not tender to form a loop

There are two algorithms for forming a minimum spanning tree: Kruskal's algorithm and Prim's algorithm.

Kruskal's algorithm

Given a connected network N with n vertices, first construct a graph G consisting of n vertices without any edges, in which each vertex forms a connected component by itself, and continuously finds the smallest one from the edges of N , if the two vertices of the edge come from different connected components, then the edge is assumed to be in G. Repeat this until all vertices are on the same connected component.
write picture description here
Let's take another example:

  1. Create a new graph with only vertices and no edges
  2. Sort the weights of the edges in the original graph from small to large
  3. We have 5 vertices so we need 4 edges
  4. With the help of the union check set written before , if the two vertices are not in a set, then the edge is assumed to be in the new graph; otherwise, continue to look at the next edge.
    The specific arrangement is as follows:
    write picture description here
    Code:
    typedef Graph<V, W, IsDirect> Self;
    typedef Node LinkEdge;
    Self Kruskal()
    {
        Self g;
        g._v = _v;//新建一个图
        g._linkEdges.resize(_v.size());
        vector<LinkEdge*> edges;
        for (size_t i = 0; i < _v.size(); i++)
        {
            LinkEdge* pCur = _linkEdges[i];     
            while (pCur)
            {
                if (IsDirect || (!IsDirect && pCur->_src < pCur->_dst))//保存边的权值。
                                                   //无向图只需要保存一次,保存src<dst
                    edges.push_back(pCur);
                pCur = pCur->_pNext;
            }       
        }

        class Compare
        {
        public:
            bool operator()(const LinkEdge* left, const LinkEdge* right)
            {
                return left->_weight < right->_weight;
            }
        };
        sort(edges.begin(), edges.end(), Compare());//将保存的边的权值,从小到大排序

        size_t count = _v.size() - 1;//从前往后取n-1条边
        UnionFind u(_v.size());
        for (size_t i = 0; i < edges.size(); i++)
        {
            LinkEdge* pCur = edges[i];
            size_t srcRoot = u.FindRoot(pCur->_src);
            size_t dstRoot = u.FindRoot(pCur->_dst);
            if (srcRoot != dstRoot)//若两个顶点不在同一个集合,才将边加上
            {
                g._Add(pCur->_src, pCur->_dst, pCur->_weight);
                if (!IsDirect)//false为无向图
                    g._Add(pCur->_dst, pCur->_src, pCur->_weight);

                u.Union(pCur->_src, pCur->_dst);//合并
                count--;
                if (count == 0)
                    break;
            }
        }
        if (count > 0)
            cout << "最小生成树非法" << endl;
        return g;
    }

Prime algorithm

write picture description here
1. Given an empty graph with only vertices;
2. Add 10 to the spanning tree with the smallest weight of 10;
3. In the original graph, the edge associated with A and B has the smallest weight of 30, and add 30 to the spanning tree. In the spanning tree;
4. For the edges related to A, B, and E in the original graph, the smallest weight is 30, and 30 is added to the spanning tree;
5. And so on, until all vertices are connected.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325668949&siteId=291194637