【数据结构】图的模拟实现(临接矩阵法)

什么是图:

图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V , E), 其中顶点集合V={ x| x属于某个数据对象集} 是有穷非空集合;E = {(x,y) | x,y属于V } 或者 E = { (x , y ) | x,y属于V && Path( x , y) }是顶点间关系的有穷集合,也叫做边的集合。(x, y)表示 x 到 y 的一条双向通路,即(x , y)是无方向的。

图的相关概念:

(1)顶点和边: 图中节点称为顶点,第i个节点记作Vi 。两个顶点Vi 和Vj 相关联称作顶点Vi 和顶点 Vj 之间有一条边,图中的第k条边记作(Vi ,Vj)或 < Vi
,Vj>。

(2)有向图和无向图: 在有向图中,顶点对< x, y >是有序的,顶点对< x , y>称为顶点x到顶点y 的一条边,< x,y> 与 < y,x >是两条不同的边。 在无向图中,顶点对< x,y>是无序的,< x, y> 与 < y,x >表示同一条边。
这里写图片描述

(3)完全图:在有n个顶点的无向图中,若有 n*(n-1) / 2条边,即任意两个顶点之间有且仅有一条边,则此图为无向完全图。在n个顶点的有向图中,若有 n *(n-1) 条边,即任意两个顶点之间有且仅有方向相反的边,则称此图为有向完全图。
这里写图片描述

(4)邻接顶点: 在无向图G中,若( u,v) 是 E (G) 中的一条边,则称 u和 v 互为邻接顶点,并称边(u,v)依附于顶点u 和 v ;在有向图G中,若< u,v >是E(G)中的一条边,则称顶点u邻接到v,顶点v邻接自顶点u,并称边< u,v>与顶点u和顶点v相关联。

(5)顶点的度: 顶点v的度是指与它相关联的边的条数,记作deg(v) 。在有向图中,顶点的度等于该顶点的入度与出度之和,其中顶点v的入度是以v为终点的有向边的条数,记作indev(v); 顶点v的出度是以v为起始点的有向边的条数,记作outdev(v) 。因此:dev(v)=indev(v)+outdev(v);
对于无向图,顶点的度等于该顶点的入度和出度,即dev(v)=indev(v)=outdev(v)

(6) 路径: 在图G=( V , E )中,若从顶点Vi出发有一组边使其可达到顶点Vj,则称顶点Vi到顶点Vj的顶点序列为从顶点Vi到顶点Vj的路径。

(7) 权:边附带的数据信息。
这里写图片描述

(8)路径长度: 对于不带权的图,一条路径的路径长度是指该路径上的边的条数;对于带权的图,一条路径的路径长度是指该路径上各个边权值的总和。

(9)简单路径与回路:若路径上各顶点V1,V2,V3,…,Vm均不重复,则称这样的路径为简单路径。若路径上第一个顶点V1和最后一个顶点Vm重合,则称这样的路径为回路或环。

(10)子图: 设图G={ V ,E}和图G1={V1,E1},若V1属于E,则称G1是G的子图。
这里写图片描述

(11)连通图: 在无向图中,若从顶点V1到顶点V2有路径,则称顶点V1与顶点V2是连通的。如果图中任意一对顶点都是连通的,则称此图为连通图。
这里写图片描述

(12)强连通图:在有向图中,若在每一对顶点Vi和Vj之间都存在一条从Vi到Vj的路径,也存在一条从Vj到Vi的路径,则称此图是强连通图。
这里写图片描述

(13)生成树:一个连通图的最小连通子图称作该图的生成树。有n个顶点的连通图的生成树有n个顶点和n-1条边。
这里写图片描述

图的模拟实现:

邻接矩阵法:
将所有的顶点信息组织成一个顶点表,然后利用一个矩阵来表示各顶点之间的邻接关系。
使用二维数组表示一个矩阵,G.Edge[n][n]。
这里写图片描述
w( i , j ) 表示的是权值。
这里写图片描述

代码实现:

#pragma once
#include<iostream>
#include<vector>
#include<assert.h>

using namespace std;

//临接矩阵法模拟实现图
template<class V,class W,bool digraph=false>
class Graph
{
public:
    Graph(V* array, size_t size)
        :_v(array, array + size)
    {
        _edges.resize(size);
        size_t i = 0;
        for (i = 0; i < size; i++)
        {
            _edges[i].resize(size);
        }
    }
    //添加边源目标权值
    void Addedges(const V& src, const V& dst, const W& w)
    {
        size_t srcIndex = GetVertexIndex(src);
        size_t dstIndex = GetVertexIndex(dst);

        _edges[srcIndex][dstIndex] = w;    //赋权值
        if (digraph == false)          //是无向图
        {
            _edges[dstIndex][srcIndex] = w;
        }
    }
    //获取顶点的度
    int getCount(const V& v)
    {
        int count = 0;
        size_t i = 0;
        int set = GetVertexIndex(v);
        for (i = 0; i < _v.size(); i++)
        {
            if (_edges[set][i] !=0)
                count++;
        }
        return count;
    }

    //打印
    void Display()
    {
        size_t i = 0,j=0;
        size_t size= _v.size();
        for (i = 0; i < size; i++)
        {
            for (j = 0; j < size; j++)
            {
                printf("%2d ",_edges[i][j]);
            }
            cout << endl;
        }
        cout << endl;
    }
private:
    //获取顶点下标
    size_t GetVertexIndex(const V& v)
    {
        size_t i = 0;
        for (i = 0; i < _v.size(); i++)
        {
            if (v == _v[i])
                return i;
        }
        assert(false);
        return -1;
    }

private:
    vector<V> _v;     //顶点集合
    vector<vector<W>> _edges;    //二维数组邻接矩阵
};

void test()
{
    char* p = "ABCDE";
    Graph<char, int,true> g(p, strlen(p));
    g.Addedges('A', 'D', 10);
    g.Addedges('A', 'E', 20);
    g.Addedges('B', 'C', 10);
    g.Addedges('B', 'D', 20);
    g.Addedges('B', 'E', 30);
    g.Addedges('C', 'E', 40);

    g.Display();
    cout << g.getCount('B') << endl;
}

运行结果:
(有向图)
这里写图片描述

(无向图)
这里写图片描述

猜你喜欢

转载自blog.csdn.net/lz201788/article/details/80025378
今日推荐