图的链式表示
// 图的相邻矩阵表示方法
#include <iostream>
#include <queue>
using namespace std;
#define N 5 // 定义图的顶点数
///*********** Graph.h ************//
//图的基类
#define UNVISITED 0
#define VISITED 1
#define INFINITE 0x7fffffff
//Edge类
class Edge
{
public:
int weight; //weight是边的权
int from; //from是边的始点
int to; //to是边的终点
Edge() // 构造函数
{
from = -1;
to = -1;
weight = 0;
}
Edge(int f,int t,int w) // 构造函数
{
from=f;
to=t;
weight=w;
}
bool operator < (const Edge &arg)
{
return (this->weight < arg.weight);
};
bool operator == (const Edge &arg)
{
return (this->weight == arg.weight);
};
bool operator > (const Edge &arg)
{
return (this->weight > arg.weight);
};
bool operator <= (const Edge &arg)
{
return (this->weight <= arg.weight);
};
bool operator >= (const Edge &arg)
{
return (this->weight >= arg.weight);
};
};
//图基类
class Graph
{
public:
int numVertex; //图的顶点的个数
int numEdge; //图的边的数目
int *Mark; /*Mark指针指向保存有图的顶点的标志位的数组,标志位用来标记某顶点是否被访问过*/
int *Indegree; //Indegree指针指向保存有图的顶点的入度的数组
Graph(int numVert) //构造函数
{
numVertex = numVert; //确定图的顶点的个数
numEdge = 0; //确定图的边的数目
Indegree = new int[numVertex]; /*为保存图的顶点的入度申请数组,Indegree为数组指针*/
Mark = new int[numVertex]; /*为图的顶点的标志位申请数组,Mark为数组指针*/
for (int i = 0; i < numVertex; i ++) /*确定图的顶点的标志位和入度,即所有顶点的标志位初始化为未被访问过,入度初始化为0*/
{
Mark[i] = UNVISITED;
Indegree[i] = 0;
}
}
~Graph() //析构函数
{
delete [] Mark;
delete [] Indegree;
}
virtual Edge FirstEdge(int oneVertex) // 返回与顶点oneVertex相关联的第一条边
{
Edge myEdge;
myEdge.from = oneVertex;
myEdge.to = -1;
return myEdge;
}
virtual Edge NextEdge(Edge preEdge) // 返回与边PreEdge有相同关联顶点的下一条边
{
return preEdge;
}
int VerticesNum() //返回图的顶点个数
{
return numVertex;
}
int EdgesNum() //返回图的边数
{
return numEdge;
}
int FromVertex(Edge oneEdge) // 返回oneEdge的始点
{
return oneEdge.from;
}
int ToVertex(Edge oneEdge) // 返回oneEdge的终点
{
return oneEdge.to;
}
int Weight(Edge oneEdge) // 返回oneEdge的权值
{
return oneEdge.weight;
}
bool IsEdge(Edge oneEdge) //如果oneEdge是边则返回TRUE,否则返回FALSE
{
if (oneEdge.weight > 0 && oneEdge.weight < INFINITE && oneEdge.to >= 0)
return true;
else
return false;
}
virtual void setEdge(int from, int to, int weight) = 0;
virtual void delEdge(int from, int to) = 0;
};
//*************** Link.h **************//
struct listUnit //邻接表表目中数据部分的结构定义
{
int vertex; //边的终点
int weight; //边的权
};
template<class Elem> //链表元素
class Link
{
public:
Elem element; //表目的数据
Link *next; //表目指针,指向下一个表目
Link(const Elem& elemval, Link *nextval = NULL) //构造函数
{
element = elemval;
next = nextval;
}
Link(Link *nextval = NULL) //构造函数
{
next = nextval;
}
};
template<class Elem> //链表
class LList
{
public:
Link<Elem>* head; //head指针并不储存任何实际元素,其存在只是为了操作方便
LList() //构造函数
{
head = new Link<Elem>();
}
void removeall() //释放边表所有表目占据的空间
{
Link<Elem> *fence;
while(head != NULL) //逐步释放每个表目占据的空间
{
fence = head;
head = head->next;
delete fence;
}
}
~LList() //析构函数
{
removeall();
}
};
class Graphl: public Graph
{
private:
LList<listUnit> *graList; //graList是保存所有边表的数组
public:
Graphl(int numVert):Graph(numVert) //构造函数
{
graList = new LList<listUnit>[numVertex]; /*为graList数组申请空间,图有
numVertex个顶点,则有numVertex个边表*/
}
~Graphl() //析构函数
{
delete [] graList; //释放空间
}
Edge FirstEdge(int oneVertex) //返回顶点oneVertex的第一条边
{
Edge myEdge; //边myEdge将作为函数的返回值
myEdge.from = oneVertex; //将顶点oneVertex作为边myEdge的始点
/*graList[oneVertex].head保存的是顶点oneVertex的边表,
temp->next指向顶点oneVertex的第一条边(如果temp->next
不为null)*/
Link<listUnit> *temp = graList[oneVertex].head;
if(temp->next != NULL) //如果顶点oneVertex的第一条边确实存在
{
myEdge.to = temp->next->element.vertex;
myEdge.weight = temp->next->element.weight;
}
/*如果找到了顶点oneVertex的第一条边,则返回的myEdge确实是一条边;如果没有
找到顶点oneVertex的第一条边,则myEdge的成员变量to为-1,根据IsEdge函数判
断可知myEdge不是一条边*/
return myEdge;
}
Edge NextEdge(Edge preEdge) // 返回与边PreEdge有相同关联顶点的下一条边
{
Edge myEdge; // myEdge的初始成员变量to为-1
myEdge.from = preEdge.from; // 将边的始点置为与上一条边的相同
Link<listUnit> *temp = graList[preEdge.from].head; // temp指向边表头一个
while (temp->next != NULL && temp->next->element.vertex <= preEdge.to)
temp = temp->next; // 确定边preEdge的位置
if (temp->next != NULL) // 边preEdge的下一条边存在
{
myEdge.to = temp->next->element.vertex;
myEdge.weight = temp->next->element.weight;
}
return myEdge; // 如果没有找到第一条边,myEdge.to=-1
}
void setEdge(int from,int to,int weight) //为图设定一条边
{
Link<listUnit> *temp = graList[from].head; /*graList[from].head保存的是顶点from的
边表,temp->next指向顶点from的第一条边
(如果temp->next不为null)*/
while(temp->next != NULL && temp->next->element.vertex < to)
temp = temp->next; /*确定边(from,to)或<from,to>在边表中的位置,如果不存在,
则边(from,to)或<from,to>为新加的一条边*/
if(temp->next == NULL)
{
/*边(from,to)或<from,to>在边表中不存在且在边表中其后
已无其它边,则在边表中加入这条边*/
temp->next = new Link<listUnit>;
temp->next->element.vertex = to;
temp->next->element.weight = weight;
numEdge++;
Indegree[to]++;
return;
}
if(temp->next->element.vertex == to)
{
/*边(from,to)或<from,to>在边表中已存在,
故只需要改变边的权值*/
temp->next->element.weight = weight;
return;
}
if(temp->next->element.vertex>to)
{
/*边(from,to)或<from,to>在边表中不存在,但在边表中
其后存在其它边,则在边表中插入这条边*/
Link<listUnit> *other = temp->next;
temp->next = new Link<listUnit>;
temp->next->element.vertex = to;
temp->next->element.weight = weight;
temp->next->next = other;
numEdge++;
Indegree[to]++;
return;
}
}
void delEdge(int from, int to) //删掉图的一条边
{
Link<listUnit> *temp = graList[from].head; /*graList[from].head保存的是顶点from的边表,temp->next指向顶点from的第一条边(如果temp->next不为null)*/
while(temp->next != NULL && temp->next->element.vertex<to)
temp = temp->next; /*确定边(from,to)或<from,to>在边表中的位置(如果该边存在)*/
if(temp->next == NULL)
return; //边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
if(temp->next->element.vertex>to)
return; //边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
if(temp->next->element.vertex == to)
{
/*边(from,to)或<from,to>在边表中存在且确
定了该边在边表中的位置,则从边表中将其删掉*/
Link<listUnit> *other = temp->next->next;
delete temp->next;
temp->next = other;
numEdge--;
Indegree[to]--;
return;
}
}
void IniGraphl(Graphl *Graphl, int A[N][N]);
void DFS(Graph& G, int v);
void BFS(Graph& G, int v);
void Visit(Graph &G, int v);
};
// 函数功能:初始化图
void Graphl::IniGraphl(Graphl *Graphl, int A[N][N])
{
for (int i = 0; i < N; i ++)
{
for (int j = 0; j < N; j ++)
{
if (A[i][j] > 0)
Graphl->setEdge(i, j, A[i][j]);
}
}
}
//函数功能:深度优先搜索算法实现
void Graphl::DFS(Graph& G, int v) //深度优先搜索算法实现
{
G.Mark[v] = VISITED; //访问顶点v,并标记其标志位
Visit(G,v);
//访问V邻接到的未被访问过的顶点,并递归地按照深度优先的方式进行周游
for(Edge e=G.FirstEdge(v); G.IsEdge(e); e=G.NextEdge(e))
if(G.Mark[G.ToVertex(e)]== UNVISITED)
DFS(G, G.ToVertex(e));
}
// 函数功能:广度优先搜索
void Graphl::BFS(Graph& G, int v) // 广度优先搜索算法的实现
{
using std::queue;
queue<int> Q; // 初始化广度优先周游要用到的队列
Visit(G,v); // 问顶点v,并标记其标志位
G.Mark[v] = VISITED;
Q.push(v); // v入队
while (!Q.empty()) // 如果队列仍然有元素
{
int u = Q.front (); // 队列顶部元素
Q.pop(); // 队列顶部元素出队
// 该顶点邻接到的每一个未访问顶点都入队
for (Edge e = G.FirstEdge(u); G.IsEdge(e); e = G.NextEdge(e))
if (G.Mark[G.ToVertex(e)] == UNVISITED)
{
Visit(G, G.ToVertex(e));
G.Mark[G.ToVertex(e)] = VISITED;
Q.push(G.ToVertex(e)); // 入队
}
}
}
// 函数功能:显示顶点
void Graphl::Visit(Graph &G, int v)
{
cout << 'V' << v <<" ";
}
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()
{
Graphl aGraphl(N); // 建立图
aGraphl.IniGraphl(&aGraphl, A); // 初始化图
cout << "DFS: ";
aGraphl.DFS(aGraphl, 0);
cout << endl;
for (int i = 0; i < aGraphl.VerticesNum(); i ++) //把Mark改回UNVISITED
aGraphl.Mark[i] = UNVISITED;
cout << "BFS: ";
aGraphl.BFS(aGraphl, 0);
cout << endl;
return 0;
}