什么是图:
图是由顶点集合及顶点间的关系组成的一种数据结构: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;
}
运行结果:
(有向图)
(无向图)