听完James老师的课,就想着把图的邻接矩阵表示法写成一个模板。
邻接矩阵适合表示稠密图,对于稀疏图,应该用链表实现才合算。
同时邻接矩阵的遍历的时间复杂度是O(n^2),而邻接表则是O(n + e)。
n表示顶点数量,e表示边数量。
对James老师的实现方式我做了一些修改。
- 由于要设置成模板,所以将表示顶点的类内置(in-class)。
- 对部分虽然通俗易懂但是略显冗余的代码做了精简。
- 广度优先我认为用队列实现更佳,重写了实现代码。
要注意的是: - 由于许多编译器不支持类模板的头文件与实现文件分离编译,所以把它们都放在头文件中。
- 在大数据遍历的过程中,局部变量造成的额外内存开销还是很客观的,因此,应当将参数列表都改成 const 的引用。为了便于阅读,这边我没有这样处理。
下面是MyMap.h的实现代码:
#ifndef MYMAP_H
#define MYMAP_H
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
template <typename T>
class MyMap {
public:
MyMap(int capacity);
~MyMap();
//添加的顶点对应的索引依次为0 ... capacity-1.
bool addVertex(T data);
void resetVertex();
//分别给有向图和无向图添加边。
bool setValue2Matrix4DirectedGraph(int row, int col, int val = 1);
bool setValue2Matrix4UndirectedGraph(int row, int col, int val = 1);
void DFS(int vertexIndex) const; //depth first search.
void BFS(int vertexIndex) const; //breadth first search.
private:
bool isAvailable(int row, int col) const; //row, col合法性判断
int getValueFromMatrix(int row, int col) const;
private:
struct Vertex { //默认访问权限 -> public
T data;
bool isVisited;
};
int capacity; //最多可容纳顶点数
int cntV; //已添加顶点数
Vertex *arrV; //顶点数组
int *pMatrix; //邻接矩阵
};
template <typename T>
MyMap<T>::MyMap(int capacity) {
this->capacity = capacity;
cntV = 0;
arrV = new Vertex[capacity];
pMatrix = new int[capacity * capacity];
memset(pMatrix, 0, capacity * capacity * sizeof(int));
}
template <typename T>
MyMap<T>::~MyMap() {
delete[] arrV;
delete[] pMatrix;
}
template <typename T>
bool MyMap<T>::addVertex(T data) {
if(cntV == capacity) return false;
arrV[cntV].data = data;
arrV[cntV++].isVisited = false;
return true;
}
template <typename T>
void MyMap<T>::resetVertex() {
for(int i = 0; i < cntV; ++i)
arrV[i].isVisited = false;
}
template <typename T>
bool MyMap<T>::setValue2Matrix4DirectedGraph(int row, int col, int val) {
if(!isAvailable(row, col)) return false;
pMatrix[row * capacity + col] = val;
return true;
}
template <typename T>
bool MyMap<T>::setValue2Matrix4UndirectedGraph(int row, int col, int val) {
if(!isAvailable(row, col)) return false;
pMatrix[row * capacity + col] = pMatrix[col * capacity + row] = val;
return true;
}
template <typename T>
void MyMap<T>::DFS(int vertexIndex) const {
cout << arrV[vertexIndex].data << " ";
arrV[vertexIndex].isVisited = true;
for(int i = 0; i < cntV; ++i) {
if(getValueFromMatrix(vertexIndex, i) > 0 && !arrV[i].isVisited)
DFS(i);
}
}
template <typename T>
void MyMap<T>::BFS(int vertexIndex) const {
queue<int> que;
que.push(vertexIndex);
while(!que.empty()) {
int index = que.front();
que.pop();
if(!arrV[index].isVisited) {
cout << arrV[index].data << " ";
arrV[index].isVisited = true;
}
for(int i = 0; i < cntV; ++i) {
if(getValueFromMatrix(index, i) > 0 && !arrV[i].isVisited)
que.push(i);
}
}
}
template <typename T>
bool MyMap<T>::isAvailable(int row, int col) const {
return 0 <= row && row < capacity && 0 <= col && col < capacity;
}
template <typename T>
int MyMap<T>::getValueFromMatrix(int row, int col) const {
if(!isAvailable(row, col)) return -1;
return pMatrix[row * capacity + col];
}
#endif
这是测试文件代码:
int main(void) {
MyMap<char> myMap(8);
for(char ch = 'a'; ch <= 'h'; ++ch)
myMap.addVertex(ch);
myMap.setValue2Matrix4UndirectedGraph(0, 1);
myMap.setValue2Matrix4UndirectedGraph(0, 3);
myMap.setValue2Matrix4UndirectedGraph(1, 2);
myMap.setValue2Matrix4UndirectedGraph(1, 5);
myMap.setValue2Matrix4UndirectedGraph(3, 6);
myMap.setValue2Matrix4UndirectedGraph(3, 7);
myMap.setValue2Matrix4UndirectedGraph(6, 7);
myMap.setValue2Matrix4UndirectedGraph(2, 4);
myMap.setValue2Matrix4UndirectedGraph(4, 5);
myMap.resetVertex();
cout << endl << "深度优先:";
myMap.DFS(0); //A B C E F D G H
myMap.resetVertex();
cout << endl << "广度优先:";
myMap.BFS(0); //A B D C F G H E
cout << endl;
return 0;
}