图的概念,邻接表,邻接矩阵表示复习

一、图的基本知识

1、图的基本表示方法:G=(V,E)

2、图的分类

无向图

有向图

3、图的一些基本概念

完全图

在有n个顶点的无向图中,有(n-1)*n/2条边,任意两个顶点都有一条边。

在有n个顶点的有向图中,有(n-1)*n条边,任意两个顶点都有两条边。

邻接顶点

在无向图中,若(u,v)是E(G)中的一条边,则u,v互为邻接顶点,并称边(u,v)依附于顶点u,v。

在有向图中,若(u,v)是E(G)中的一条边,则称u邻接到v,v邻接自顶点u,称u,v相关联。

顶点的度

顶点与他相关联的边的条数,记作dev(v)

出度(indev):以v为终点的边。

入度(outdev):以v为起点的边。

在无向图中,顶点的出度,入度,度相同。dev(v)=indev(v)=outdev(v)。

在有向图中,顶点的度是出度于入度的和。dev(v)=indev(v)+outdev(v)。

路径

在图G(V,E)中,有一组边能从vi出发到vj,这组边构成的是路径。

路径长度

若边有权值,则长度是边的权值总和。

若边没有权值,则长度是边的个数。

简单路径与回路

简单路径

若路径上各顶点均不重复,则为简单路径。

回路

若简单路径的起点与终点重复就是回路。

子图

子图的边是父图的部分边,子图的顶点是父图的部分顶点。

连通图(无向图的专有概念)

在无向图中,从vi到vj有路径就称vi到vj连通。若任意一对顶点连通就是连通图。(只要图中没有孤岛就是连通图)

强制连通图(有向图专有概念)

在有向图中,每一对顶点vi,vj,从vi到vj有路径,从vj到vi也有路径,则称强制连通图。

生成树

一个连通图的最小连通子图是生成树。有n个顶点的连通图的生成树有n个顶点和n-1条边。

最小生成树

权值最小的生成树。

二、邻接表表示图

1、邻接表结构

2、邻接表优势

适合存储稀疏图。

查找一个顶点相连的所有边。

3、邻接表代码实现

首先,我们需要用struct Edge来把边表示出来。

​//模版的W指权值的数据类型
template<class W>
struct Edge
{
    int _dsti;       // 终点下标
    W _w;            // 权值大小
    Edge<W> _next;   // 链接指针

    Edge(int dsti, const W& w)
        :_dsti(dsti)
        ,_w(w)
        ,_next(nullptr)
    {}
};

​

我们这里手动输入图中的节点和权值,所以Graph构造函数中要有顶点的集合和个数。

// 类型形参:V表示顶点数据类型,W表示权值数据类型
// 非类型形参:若权值不传参数就默认是INT_MAX,同理默认是无向图
template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{
    typedef Edge<W> Edge;
public:
    Graph(const V* a, int n)
    {
        _vertexs.reserve(n);
        for(int i = 0; i < n; i++)
        {
            _vertexs.push_back(a[i]);
            _indexmap[a[i]] = i;
        }
        _tables.resize(n, nullptr);
    }
private:
    vector<V> _vertexs;     // 顶点数组
    map<V, int> _indexmap;  // 顶点下标对应
    vector<Edge*> _tables;  // 邻接表集合
}

邻接表中添加边操作

基本原理:

因为链表的结构,所以我们采用头插法。

第一步,要找到起点srci在_tables的位置,即_tables[srci]。

第二步,要new一个Edge,存终点和权值。

第三部,头插。

特别的,若是无向图由于对称性,我们还要将终点起点交换,再进行一次上述操作。

void AddEdge(const V& src, const V& dst, const W& w)
{
    // 先去顶点下标
    int srci = GetIndex(src);
    int dsti = GetIndex(dst);
    
    // src->dst
    Edge* eg = new(dsti, w);
    eg->next = _tables[srci];
    _tables[srci] = eg;
    
    // 若是无向图,还要交换一次
    if(Direction == false)
    {
        Edge* eg = new(srci, w);
        eg->next = _tables[dsti];
        _tables[dsti] = eg;
    }
}

三、邻接矩阵表示图

1、邻接矩阵结构

2、邻接矩阵优势

快速查找所有边的权值。

3、邻接矩阵代码实现

与邻接表成员函数类似,依然有_vertexs,_indexmap。但是要存矩阵所以是_matrix。

template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{
public:
	Graph(const V* a, size_t n)
	{
		_vertexs.reserve(n);
		for (int i = 0; i < n; i++)
		{
			//先创建顶点和映射关系
			_vertexs.push_back(a[i]);
			_indexmap[a[i]] = i;
		}

		//创建n*n矩阵
		_matrix.resize(n);
		for (int i = 0; i < n; i++)
		{
			//默认全是孤独的
			_matrix[i].resize(n, MAX_W);
		}
	}
private:
	vector<V> _vertexs;         //顶点集合
	map<V, int> _indexmap;      //顶点的下标集合
	vector<vector<W>> _matrix;  //邻接矩阵表示边的集合
};

邻接矩阵中添加边操作

基本原理:

在_matrix[srci][dsti]中存的是src->dst边的权值,所以直接赋值即可。

注意无向图对称性 ,_matrix[dsti][srci]也要赋值。

void AddEdge(const V& src, const V& dst, const W& w)
{
	size_t srci = GetVertexIndex(src);
	size_t dsti = GetVertexIndex(dst);
	_matrix[srci][dsti] = w;
	//如果是无向图要添加两次权值
	if (Direction == false)
	{
		_matrix[dsti][srci] = w;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值