7-1图论基础
图由节点和边组成。
图的分类:
有向图:边有方向
无向图:边没有方向
有权图:边有一个数值和其对应
无权图: 和上面相反
连通图:节点之间是否连通
简单图:是否存在自环边(自己到自己)或者平行边(两个节点之间有多条边)
7-2图的表示
邻接矩阵:
邻接表:
邻接表适合表示稀疏图(边比较少,图中边的个数远远少于当图是完全图时的个数)
邻接矩阵适合表示稠密图(边比较多,如完全图,每两个节点之间都相连)
邻接表中查询是否已经存在边的操作,其时间复杂度是O(n),为了保证效率,在用邻接表表示图时,可以先不考虑平行边的问题
dense_graph.h:
#ifndef DENSE_GRAPH_H_INCLUDED
#define DENSE_GRAPH_H_INCLUDED
#include <iostream>
#include <vector>
#include <cassert>
using namespace std;
///稠密图----邻接矩阵
class DenseGraph{
private:
int n; /顶点的个数
int m; /边的个数
vector<vector<bool>> g; 邻接矩阵
bool directed;
public:
/构造函数---顶点个数,是否是有向图
DenseGraph(int n,bool directed)
{
n=n;
directed=directed;
m=0;
创建n*n的矩阵
for(int i=0;i<n;i++)
{
g.push_back(vector<bool>(n,false));
}
}
析构函数
~DenseGraph(){}
返回点的个数
int V()
{
return n;
}
返回边的个数
int E()
{
return m;
}
添加v和w之间的边
void addEdge(int v,int w)
{
//判断v和w是否合法
assert(v>=0 && v<n);
assert(w>=0 && w<n);
//判断v和w之间是否存在边,好处:自动去掉平行边
if(hasEdge(v,w))
{
return ;
}
//添加从v->w的边
g[v][w]=true;
//如果是无向图
if(!directed)
{
//添加从w->v的边
g[w][v]=true;
}
//边数自增
m++;
}
//判断v和w之间是否有边 //好处:O(1)的时间
bool hasEdge(int v,int w)
{
assert(v>=0 && v<n);
assert(w>=0 && w<n);
return g[v][w];
}
};
#endif // DENSE_GRAPH_H_INCLUDED
sparse_graph.h:
#ifndef SPARSE_GRAPH_H_INCLUDED
#define SPARSE_GRAPH_H_INCLUDED
#include <iostream>
#include <vector>
#include <cassert>
using namespace std;
//稀疏图---邻接表
class SparseGraph{
private:
int n; //点的个数
int m; //边的个数
bool directed; //是否有向
vector<vector<int>> g; //邻接表
public:
//构造函数
SparseGraph(int n,bool directed)
{
n=n;
m=0;
directed=directed;
for(int i=0;i<n;i++)
{
g.push_back(vector<int>());
}
}
//析构函数
~SparseGraph(){}
int V()
{
return n;
}
int E()
{
return m;
}
void addEdge(int v,int w)
{
assert(v>=0&& v<n);
assert(w>=0&& w<n);
//先不管平行边,后面再进行处理
g[v].push_back(w);
if(!directed && v!=w) //v=w表示是自环边,自环边只添加一次
{
g[w].push_back(v);
}
m++;
}
bool hasEdge(int v,int w)
{
assert(v>=0&& v<n);
assert(w>=0&& w<n);
for(int i=0;i<g[v].size();i++)
{
if(g[v][i]==w)
{
return true;
}
}
return false;
}
};
#endif // SPARSE_GRAPH_H_INCLUDED