图的表示:
测试代码
主要有两种,邻接矩阵和邻接表,前者空间复杂度,O(V2),后者为O(V+E)。因此,除非非常稠密的图(边非常多),一般后者优越于前者。
上篇讨论了邻接矩阵的实现,本篇讨论邻接表的实现
GraphLink.h
#include "Graph.h"
#include <iostream>
#include <queue>
using std::cout;
using std::cin;
using std::endl;
using std::queue;
#define N 5 // 定义图的顶点数
template <typename T> class LList;
template <typename T> class GraphLink;
struct ListUnit//邻接表表目中数据部分的结构定义
{
int weight; //边的权
int vertex;//边的终点
};
template <typename T>
class Link //链表元素
{
friend class GraphLink<T>;
friend class LList<T>;
T element;//表目的数据
Link<T> *next; //表目指针,指向下一个表目
Link(const T &e,Link<T> *n = nullptr)//构造函数
{
element = e;
next = n;
}
Link(Link<T> *n = nullptr)//构造函数
{
next = n;
}
};
template <typename T>
class LList
{
private:
void removeAll() //释放边表所有表目占据的空间
{
Link<T> *p = head->next;
Link<T> *temp = nullptr;
while(p != nullptr)
{
temp = p;
p = p->next;
delete temp;
}
}
public:
Link<T> *head;//head指针并不储存任何实际元素,其存在只是为了操作方便
LList()//构造函数
{
head = new Link<T>();
}
~LList()
{
removeAll();
}
};
template <typename T>
class GraphLink : public Graph
{
private:
LList<ListUnit> *grapList; //graList是保存所有边表的数组
public:
GraphLink(int numVert) : Graph(numVert)
{
/*为graList数组申请空间,图有numVertex个顶点,则有numVertex个边表*/
grapList = new LList<ListUnit>[numVert];
}
~GraphLink()
{
delete []grapList;
}
virtual Edge firstEdge(int oneVertex)// 返回与顶点oneVertex相关联的第一条边
{
Edge edge;
edge.from = oneVertex;//将顶点oneVertex作为边edge的始点
edge.to = -1;
/*graList[oneVertex].head保存的是顶点oneVertex的边表,
head->next指向顶点oneVertex的第一条边(如果head->next
不为null)*/
Link<ListUnit> *p = grapList[oneVertex].head->next;
if(p != nullptr)
{
edge.to = p->element.vertex;
edge.weight = p->element.weight;
}
return edge;
}
virtual Edge nextEdge(Edge preEdge)// 返回与边PreEdge有相同关联顶点的下一条边
{
Edge edge;
edge.from = preEdge.from;
edge.to = -1;
Link<ListUnit> *p = grapList[preEdge.from].head->next;
while(p != nullptr && p->element.vertex <= preEdge.to)// 确定边preEdge的位置
{
p = p->next;
}
if(p)// 边preEdge的下一条边存在
{
edge.to = p->element.vertex;
edge.weight = p->element.weight;
}
return edge;
}
void setEdge(int from, int to, int weight)
{
Link<ListUnit> *p = grapList[from].head->next;
Link<ListUnit> *pre = grapList[from].head;
/*确定边(from,to)或<from,to>在边表中的位置,如果不存在,
则边(from,to)或<from,to>为新加的一条边*/
while(p != nullptr && p->element.vertex < to)
{
pre = p;//记录下前一节点
p = p->next;
}
if(p == nullptr)
{
Link<ListUnit> *temp = new Link<ListUnit>();
temp->element.vertex = to;
temp->element.weight = weight;
pre->next = temp;
numEdge++;
indegree[to]++;
return;
}
/*边(from,to)或<from,to>在边表中已存在,故只需要改变边的权值*/
if(p->element.vertex == to)
{
p->element.weight = weight;
return;
}
/*边(from,to)或<from,to>在边表中不存在,但在边表中其后存在其它边,则在边表中插入这条边*/
if(p->element.vertex > to)
{
Link<ListUnit> *temp = new Link<ListUnit>();
temp->element.vertex = to;
temp->element.weight = weight;
pre->next = temp;
temp->next = p;
numEdge++;
indegree[to]++;
return;
}
}
void delEdge(int from, int to)
{
Link<ListUnit> *p = grapList[from].head->next;
Link<ListUnit> *pre = grapList[from].head;
/*确定边(from,to)或<from,to>在边表中的位置*/
while(p != nullptr && p->element.vertex < to)
{
pre = p;//记录下前一节点
p = p->next;
}
if(p == nullptr)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
{
return;
}
if(p->element.vertex > to)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
{
return;
}
if(p->element.vertex == to)
{
pre->next = p->next;
delete p;
numEdge--;
indegree[to]--;
return;
}
}
// 函数功能:初始化图
void initGraph(GraphLink &graphM,int (*A)[N],int n)
{
for (int i = 0; i < n; i ++)
{
for (int j = 0; j < N; j ++)
{
if (A[i][j] > 0)
graphM.setEdge(i, j, A[i][j]);
}
}
}
void DFS( GraphLink &graph,int vertex)
{
graph.mark[vertex] = VISITED;
visit(graph,vertex);
for(Edge edge = graph.firstEdge(vertex); graph.isEdge(edge); edge = graph.nextEdge(edge))
{
if(graph.mark[graph.toVertex(edge)] == UNVISITED)
{
DFS(graph,graph.toVertex(edge));
}
}
}
void BFS( GraphLink &graph,int vertex)
{
queue<int> q; // 初始化广度优先周游要用到的队列
q.push(vertex);
while(!q.empty())
{
int v = q.front();
q.pop();
if(graph.mark[v] == UNVISITED )
{
visit(graph,v);
graph.mark[v] = VISITED;//标记该顶点已访问
// 该顶点邻接到的每一个未访问顶点都入队
for(Edge edge = graph.firstEdge(v); graph.isEdge(edge); edge = graph.nextEdge(edge))
{
if(graph.mark[graph.toVertex(edge)] == UNVISITED)
{
q.push(graph.toVertex(edge));
}
}
}
}
}
void visit(const GraphLink &graph,int vertex)
{
cout << "V:" << vertex << "\t";
}
};
测试代码
#include "GraphLink.h"
#include <iostream>
int A[N][N] = {
// V0 V1 V2 V3 V4
/*V0*/ 0, 0, 1, 1, 0,
/*V1*/ 0, 0, 0, 1, 1,
/*V2*/ 1, 0, 0, 1, 1,
/*V3*/ 1, 1, 1, 0, 0,
/*V4*/ 0, 1, 1, 0, 0,}; //图7.2中G1表示的无向图
int main()
{
GraphLink<ListUnit> graphLink(N); // 建立图
graphLink.initGraph(graphLink, A,N); // 初始化图
cout << "DFS: ";
graphLink.DFS(graphLink, 0);
cout << endl;
for (int i = 0; i < graphLink.verticesNum(); i++) //把Mark改回UNVISITED
graphLink.mark[i] = UNVISITED;
cout << "BFS: ";
graphLink.BFS(graphLink, 0);
cout << endl;
system("pause");
return 0;
}