邻接矩阵存在的问题
如果我们的每一个顶点所连接的顶点只是周围的几个点, 那么形成的图是一个稀疏图,而我们生活中研究的大多数问题都是稀疏图问题, 比我我们研究的导航路径问题就是一个典型的稀疏图
邻接表
使用邻接矩阵方式实现一个稠密图
DenseGraph.cpp
#include <iostream>
#include <vector>
#include <cassert>
using namespace std;
// 使用邻接矩阵方式实现一个稠密图
class DenseGraph{
private:
int n, m;// 节点数和边数
bool directed; // 是否为有向图
vector<vector<bool>> g; // 图的具体数据
public:
// 构造函数
DenseGraph(int n, bool directed){
assert(n >=0);
this->n = n;
this->m = 0; // 初始化没有任何边
this->directed = directed;
// g初始化为n*n的布尔矩阵, 每一个g[i][j]均为false, 表示没有任和边
g = vector<vector<bool>>(n, vector<bool>(n, false));
}
~DenseGraph(){};
int V(){return n;} // 返回节点个数
int E(){return m;} // 返回边的个数
// 向图中添加一个边
void addEdge(int v, int w){
assert(v >=0 && v < n);
assert(w >=0 && w < n);
if (hasEdge(v, w))
return;
g[v][w] = true;
if (!directed)
g[w][v] = true;
m++;
}
// 验证图中是否有从v到w的边
bool hasEdge(int v, int w){
assert(v >=0 && v < n);
assert(w >=0 && w < n);
return g[v][w];
}
};
int main (){
DenseGraph graph1(1, 1);
DenseGraph graph2(3, 1);
return 0;
}
使用邻接表方式实现一个稀疏图
#include <iostream>
#include <vector>
#include <cassert>
using namespace std;
// 使用邻接表方式实现一个稀疏图
class SparseGraph{
private:
int n, m;// 节点数和边数
bool directed; // 是否为有向图
vector<vector<int>> g; // 图的具体数据
public:
// 构造函数
SparseGraph(int n, bool directed){
assert(n >=0);
this->n = n;
this->m = 0; // 初始化没有任何边
this->directed = directed;
// g初始化为n*n的布尔矩阵, 每一个g[i][j]均为false, 表示没有任和边
g = vector<vector<int>>(n, 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 (v != w && !directed)
g[w].push_back(v);
m++;
}
// 验证图中是否有从v到w的边
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;
}
};
int main (){
SparseGraph graph1(1, 1);
SparseGraph graph2(3, 1);
return 0;
}
通过迭代器实现邻接表方式和邻接矩阵方式迭代(遍历)统一接口
vector的迭代器
#include <iostream>
#include <vector>
using namespace std;
int main (){
// STL
vector<int> v;
for (int i = 0; i < 5; i++) {
v.push_back(i);
}
// 1 遍历;
for (int i = 0; i < v.size(); i++) {
cout<< v[i] <<", ";
}
cout <<endl;
// 2 迭代器
for (vector<int>::iterator it = v.begin(); it != v.end() ;it++) {
cout<< *it <<endl;
}
return 0;
}
邻接表的方式实现迭代并测试
#include <iostream>
#include <vector>
#include <cassert>
using namespace std;
// 使用邻接表方式实现一个稀疏图
class SparseGraph{
private:
int n, m;// 节点数和边数
bool directed; // 是否为有向图
vector<vector<int>> g; // 图的具体数据
public:
// 构造函数
SparseGraph(int n, bool directed){
assert(n >=0);
this->n = n;
this->m = 0; // 初始化没有任何边
this->directed = directed;
// g初始化为n*n的布尔矩阵, 每一个g[i][j]均为false, 表示没有任和边
g = vector<vector<int>>(n, 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);
if (hasEdge(v, w))
return;
g[v].push_back(w);
if (v != w && !directed)
g[w].push_back(v);
m++;
}
// 验证图中是否有从v到w的边
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;
}
// 邻边迭代器, 传入一个图和一个顶点,
// 迭代在这个图中和这个顶点向连的所有顶点
class adjIterator{
private:
SparseGraph &G; // 图G的引用
int v; // 顶点数
int index; // 表示索引
public:
// 构造函数
adjIterator(SparseGraph &graph, int v): G(graph){
this->v = v;
this->index = 0;
}
~adjIterator(){}
// 返回图G中与顶点v相连接的第一个顶点
int begin(){
index = 0;
if (G.g[v].size())
return G.g[v][index];
// 若没有顶点和v相连接, 则返回-1
return -1;
}
int next(){
index++;
if (index < G.g[v].size())
return G.g[v][index];
// 若没有顶点和v相连接, 则返回-1
return -1;
}
//查看是否已经迭代完了图G中与顶点v相连接的所有顶点
bool end(){
return index >= G.g[v].size();
}
};
};
int main (){
int N = 20, M = 100; // 20个顶点 100个边
SparseGraph graph(N, false);
for (int i = 0; i < M; i++) {
int a = rand()%N;
int b = rand()%N;
graph.addEdge(a, b);
}
// 遍历
for (int v = 0; v < N; v++) {
cout<< v << " : ";
SparseGraph::adjIterator adj(graph, v);
for (int w = adj.begin(); !adj.end(); w = adj.next()) {
cout<< w <<" ";
}
cout<<endl;
}
return 0;
}
邻接矩阵的方式实现迭代并测试
#include <iostream>
#include <vector>
#include <cassert>
using namespace std;
// 使用邻接矩阵方式实现一个稠密图
class DenseGraph{
private:
int n, m;// 节点数和边数
bool directed; // 是否为有向图
vector<vector<bool>> g; // 图的具体数据
public:
// 构造函数
DenseGraph(int n, bool directed){
assert(n >=0);
this->n = n;
this->m = 0; // 初始化没有任何边
this->directed = directed;
// g初始化为n*n的布尔矩阵, 每一个g[i][j]均为false, 表示没有任和边
g = vector<vector<bool>>(n, vector<bool>(n, false));
}
~DenseGraph(){};
int V(){return n;} // 返回节点个数
int E(){return m;} // 返回边的个数
// 向图中添加一个边
void addEdge(int v, int w){
assert(v >=0 && v < n);
assert(w >=0 && w < n);
if (hasEdge(v, w))
return;
g[v][w] = true;
if (!directed)
g[w][v] = true;
m++;
}
// 验证图中是否有从v到w的边
bool hasEdge(int v, int w){
assert(v >=0 && v < n);
assert(w >=0 && w < n);
return g[v][w];
}
// 邻边迭代器, 传入一个图和一个顶点,
// 迭代在这个图中和这个顶点向连的所有顶点
class adjIterator{
private:
DenseGraph &G; // 图G的引用
int v; // 顶点数
int index; // 表示索引
public:
// 构造函数
adjIterator(DenseGraph &graph, int v): G(graph){
this->v = v;
this->index = -1;
}
// 返回图G中与顶点v相连接的第一个顶点
int begin(){
// 索引从-1开始, 因为每次遍历都需要调用一次next()
index = -1;
return next();
}
// 返回图G中与顶点v相连接的下一个顶点
int next(){
// 从当前index开始向后搜索, 直到找到一个g[v][index]为true
for (index += 1; index < G.V(); index++) {
if (G.g[v][index])
return index;
}
return -1;
}
//查看是否已经迭代完了图G中与顶点v相连接的所有顶点
bool end(){
return index >= G.V();
}
};
};
int main (){
int N = 20, M = 100; // 20个顶点 100个边
DenseGraph graph(N, false);
for (int i = 0; i < M; i++) {
int a = rand()%N;
int b = rand()%N;
graph.addEdge(a, b);
}
// 遍历 On^2
for (int v = 0; v < N; v++) {
cout<< v << " : ";
DenseGraph::adjIterator adj(graph, v);
for (int w = adj.begin(); !adj.end(); w = adj.next()) {
cout<< w <<" ";
}
cout<<endl;
}
return 0;
}
我们可以看出邻接矩阵迭代的时间赋值读为On^2 而 邻接表为 On