The basic concept and realization of graph

Elements in a linear table are in a "one-to-one" relationship, elements in a tree are in a "one-to-many" relationship, and emoticons are in a "many-to-many" relationship. A graph is a complex nonlinear structure. Each element in the graph can have zero or more predecessors and zero or more successors, that is, the relationship between elements is arbitrary.

1. The concept of graph

Definition: A graph is actually a data structure composed of a set of vertices and the relationship between vertices. Usually expressed as: G(V, E), where G represents a graph, V is the set of vertices in the graph G, and E is the set of edges in the graph G.

Classification of
graphs Graphs can be divided into undirected and directed graphs .
write picture description here
The left picture is an undirected graph, which is composed of vertices and edges, and the right picture is a directed graph, which is composed of vertices and arcs. The arc has the difference between the arc head and the arc tail.

According to the edge, the graph can be divided into sparse graph and dense graph, which is a vague concept and relative.
(x,y) represents an undirected edge,

Second, the storage of pictures

1. Link matrix
The link matrix uses two arrays to store data. A one-dimensional array stores graph vertex information, and a two-dimensional array stores information about edges or arcs in the graph.
In an undirected graph, a two-dimensional array is a symmetric matrix.

Features :
0 means no edge, 1 means edge.
The degree of a vertex is the sum of the row array.
Find the vertex leading edge, and traverse the inline elements.
write picture description here
In the connected matrix of a directed graph, the sum of the rows is the out-degree, and the sum of the columns is the in-degree.
A weighted graph is called a net, and it is represented by a tie matrix: a
write picture description here
tie matrix is ​​a waste of space for graphs with fewer edges than vertices.

Advantages & Disadvantages of Concatenation Matrix
Advantages: Connectivity
Disadvantages : The path from a vertex to a point is not convenient to represent.

Code:

//领接矩阵存储
template <class V,class W,bool IsDirect=false>//默认情况下是无向图
class Graph
{
public:
    Graph()
    {}
    Graph(const V* array,size_t size)
    {
        //构造顶点
        _v.resize(size);
        for (size_t i = 0; i < size; ++i)
        {
            _v[i] = array[i];
        }

        //动态开辟二维数组
        _edges.resize(size);
        for (size_t i = 0; i < size; ++i){
            _edges[i].resize(size);
        }
    }

    ///获取顶点元素在其数组中的下标
    size_t GetIndexOfV(const V& value)
    {
        int size = _v.size();
        for (size_t i = 0; i < size; ++i){
            if (_v[i] == value)
                return i;
        }
        return -1;//返回-1表示找不到
    }

    //获取顶点的度
    size_t GetDevOfV(const V& value)
    {
        int size = _v.size();
        int dev = 0;
        int index = GetIndexOfV(value);
        if (index != -1)//该顶点存在
        {
            for (size_t i = 0; i < size; ++i){
                if (_edges[index][i] != 0)//有边
                    ++dev;
            }
            //有向图
            if (IsDirect){
                for (size_t j = 0; j < size; j++){
                    if (_edges[j][index] != 0)
                        ++dev;
                }
            }
        }
        return dev;
    }

    //添加顶点v1和v2对应的权值为weight的边
    void AddEdge(const V& v1, const V& v2, const W& weight)
    {
        int index1 = GetIndexOfV(v1);
        int index2 = GetIndexOfV(v2);

        if (index1 != -1 && index2 != -1)//两个顶点均存在
        {
            _edges[index1][index2] = weight;
            //无向图
            if (!IsDirect){
                _edges[index2][index1] = weight;
            }
        }
    }

    //图的打印
    void PrintGraph()
    {
        int size = _v.size();
        for (size_t i = 0; i < size; ++i)
        {
            for (size_t j = 0; j < size; ++j)
            {
                printf("%2d ", _edges[i][j]);
            }
            printf("\n");
        }
        printf("\n");
    }

private:
    vector<V> _v;//图的顶点
    vector<vector<W>> _edges;//任意两个顶点之间的边的权值
};

Test code:

void test1()
{
    int array[] = { 0, 1, 2, 3 };
    Graph<int, int> g(array, sizeof(array) / sizeof(array[0]));
    g.AddEdge(0, 1, 10);
    g.AddEdge(2, 1, 30);
    g.AddEdge(1, 2, 20);
    g.AddEdge(0, 3, 40);

    g.GetDevOfV(1);
    g.PrintGraph();
}

2. Link
list The storage method of combining arrays and linked lists, the vertices are stored in a one-dimensional array, and all the link points of each vertex vi form a linear list.
write picture description here

Code:

template<class W>
struct LinkEdge
{
    size_t _src;//边的起点
    size_t _dst;//边的终点
    W _weight;//边的权值
    LinkEdge* _pNext;//指向下一条边

    LinkEdge()
    {}

    //有参构造函数
    LinkEdge(const size_t& src, const size_t& dst, const W& weight)
        :_src(src)
        , _dst(dst)
        , _weight(weight)
        , _pNext(NULL)
    {}
};

//领接表存储
template <class V,class W,bool IsDirect=false>
class Graph
{
    typedef LinkEdge<W> Node;
    typedef Node* PNode;

public:
    Graph()
    {}

    Graph(const V* array, size_t size)
        :_v(array,array+size)
    {
        _linkEdges.resize(size);
    }

    //获取顶点元素在其数组中的下标
    size_t GetIndexOfV(const V& value)
    {
        int size = _v.size();
        int index = 0;
        for (size_t i = 0; i < size; ++i)
        {
            if (_v[i] == value)
                return i;
        }
        return -1;
    }

    //添加顶点为v1和v2所对应权值为weight的边(采用头插)
    void AddEdge(const V& v1, const V& v2, const W& weight)
    {
        int index1 = GetIndexOfV(v1);//起点的下标
        int index2 = GetIndexOfV(v2);//终点的下标
        PNode pSrc = _linkEdges[index1];//起点
        PNode pDst = _linkEdges[index2];//终点

        if (index1 != -1 && index2 != -1)//顶点均存在
        {
            PNode newNode =new Node(index1, index2, weight);
            newNode->_pNext = pSrc;
            _linkEdges[index1] = newNode;

            if (!IsDirect)//无向图
            {
                PNode newNode =new Node(index2, index1, weight);
                newNode->_pNext = pDst;
                _linkEdges[index2] = newNode;
            }
        }
    }

    //获取顶点的度
    int GetVDev(const V& value)
    {
        int dev = 0;
        int index = GetIndexOfV(value);
        PNode pCur= _linkEdges[index];
        while (pCur)
        {
            ++dev;
            pCur = pCur->_pNext;
        }
        return dev;
    }

    void PrintGraph()
    {
        int size = _v.size();
        for (size_t i = 0; i < size; ++i)
        {
            PNode pCur = _linkEdges[i];
            while (pCur)
            {
                cout << _v[pCur->_src] << "--->" << _v[pCur->_dst] <<" 权值"<< pCur->_weight<<endl;
                pCur = pCur->_pNext;
            }
        }
    }

    //获取边的权值
    W GetVWeight(const V& v1,const V& v2)
    {
        int index1 = GetIndexOfV(v1);//起点的下标
        int index2 = GetIndexOfV(v2);//终点的下标

        if (index1 != -1 && index2 != -1)
        {
            PNode pCur = _linkEdges[index1];
            while (pCur)
            {
                if (pCur->_dst == index2)
                    return pCur->_weight;
                pCur = pCur->_pNext;
            }
        }
    }

private:
    vector<V> _v;//存储图的顶点
    vector<PNode> _linkEdges;//存储边,结点
};

Test code:

void test2()
{
    int array[] = { 0, 1, 2, 3 };
    Graph<int, int> g(array, sizeof(array) / sizeof(array[0]));

    g.AddEdge(0, 1, 10);
    g.AddEdge(0, 2, 20);
    g.AddEdge(1, 2, 30);
    g.AddEdge(2, 1, 40);
    g.AddEdge(3, 2, 50);

    cout<<"以0为顶点的度为:"<< g.GetVDev(0)<<endl;
    g.PrintGraph();

    cout<<"0,1顶点的边的权值为:"<<g.GetVWeight(0, 1)<<endl;
}

Guess you like

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