介绍
- 学习记录
- 定义
使用方阵A[n][n]表示n个顶点之间构成的图,其中每个单元负责对一对顶点之间邻接关系进行描述
- 缺点
方阵可以描述所有可能存在的边的关系, 但是实际问题边并没有出现那么多,浪费了大量的空间; 可以使用A[n] = LIST代替(邻接列表),列表中只存放当前节点一定存在的邻接顶点
实现
//
// Created by carso on 2020/3/14.
//
#ifndef C___GRAPMATRIX_H
#define C___GRAPMATRIX_H
#include <Graph.h>
#include <Vector.h>
#include <limits.h>
// 定义顶点
template<typename Tv>
struct Vertex {
Tv data; // 数据
int inDegree, outDegree, // 入度,出度
VStatus
status; // 状态 未发现,发现,访问
int dTime, fTime; // 时间标签 (用来算法判断边类型)
int parent; // 遍历树中的父级顶点
int priority; // 遍历树中的优先级
// 构造函数
Vertex(Tv const &d = (Tv) 0) : data(d), inDegree(0), outDegree(0), status(UNDETERMINED),
dTime(-1), fTime(-1), parent(-1), priority(INT_MAX) {}
};
// 定义边
template<typename Te>
struct Edge {
Te data; // 数据
int weight; //权重
EType type; // 边类型
// 构造函数
Edge(Te const &d, int w) : data(d), weight(w), type(UNDETERMINED) {}
};
// 定义邻接矩阵
template<typename Tv, typename Te>
class GraphMatrix : public Graph {
private:
// 顶点集(向量)
Vector <Vertex<Tv>> V;
// 边集合 (邻接矩阵)
Vector <Vector<Edge<Te> *>> E;
public:
// 构造函数
GraphMatrix() { n = e = 0 }
// 析构函数
~GraphMatrix() {
// 删除所有边
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
delete E[i][j];
}
delete V[i];
}
}
// 顶点操作
// 返回特定顶点的数据
virtual Tv &vertex(int i) { return V[i].data; }
// 入度
virtual int inDegree(int i) {
return V[i].inDegree;
}
// 出度
virtual int outDegree(int i) {
return V[i].outDegree;
}
// 首个邻接顶点
virtual int firstNbr(int i) {
return nextNbr(i, n);
}
// 下一个邻接顶点, 注意不包含下标j
virtual int nextNbr(int i, int j) {
while (j > -1 && !exist(i, --j)) {}
return j;
}
// 状态
virtual VStatus &status(int i) { return V[i].status; }
// 时间标签
virtual int &dTime(int i) {
return V[i].dTime;
}
virtual int &fTime(int i) {
return V[i].fTime;
}
// 在遍历树中父节点
virtual int &parent(int i) { return V[i].parent; }
// 遍历树中的优先级
virtual int &priority(int i) {
return V[i].priority;
}
// 顶点动态操作
// 插入顶点,返回编号
virtual int insert(Tv const &vertex) {
// 各个顶点预留一条潜在的关联边
for (int i = 0; i < n; ++i) {
E[i].insert(NULL);
}
// 总顶点数+1
n++;
// 创建新边
Vector < Edge<Te> * > newEdgePoint = new Vector(n, n, (Edge<Te> *) NULL);
E.insert(newEdgePoint);
// 顶点向量增加一个顶点
return V.insert(Vertex(vertex));
}
// 删除顶点和关联边
virtual Tv remove(int i) {
// 删除可能存在的边
for (int j = 0; j < n; ++j) {
if (exists(i, j)) {
delete E[i][j];
V[j].inDegree--;
}
}
E.remove(i);
n--;
// 删除顶点
Tv vBak = V.remove(i);
// 删除所有的入边
for (int k = 0; k < n; ++k) {
if (Edge(Te) * e = E[k].remove(i)) {
delete e;
V[k].outDegree--;
}
}
return vBak;
}
// 边操作
// 边(i,j)是否存在
virtual bool exists(int i, int j) {
return i > 0 && j > 0 && i < n && j < n && (E[i][j] != NULL);
}
// 边的类型
virtual EType &type(int i, int j) {
return E[i][j]->type;
}
// 边的数据
virtual Te &edge(int i, int j) {
return E[i][j]->data;
}
// 边的权重
virtual int &weight(int i, int j) {
return E[i][j]->weight;
}
// 插入操作
virtual void insert(Te const &edge, int w, int i, int j) {
// 如果边已经存在
if (exists(i, j)) {
return;
}
// 创建新边
E[i][j] = new Edge(edge, w);
e++;
V[i].outDegree++;
V[J].inDegree++;
}
// 边删除操作
virtual Te remove(int i, int j) {
// 边不存在
if (!exists(i, j)) {
return;
}
Te edge = edge(i, j);
// 删除边
delete E[i][j];
// 维持空边
E[i][j] = NULL;
// 出度入度
V[i].outDegree--;
V[j].inDegree--;
// 边数
e--;
return edge;
}
};
#endif //C___GRAPMATRIX_H