前言
在计算机科学中,一个图就是一些顶点的集合,这些顶点通过一系列边结对(连接)。顶点用圆圈表示,边就 是这些圆圈之间的连线。顶点之间通过边连接。注意:顶点有时也称为节点或者交点,边有时也称为链接。 社交网络,每一个人就是一个顶点,互相认识的人之间通过边联系在一起, 边表示彼此的关系。这种关系可以 是单向的,也可以是双向的!
图的表示
1.邻接列表:在邻接列表实现中,每一个顶点会存储一个从它这里开始的相邻边的列表。比如,如果顶点 B 有一条边到 A、 C 和 E,那么 A 的列表中会有 3 条边。
邻接列表只描述指向外部的边。B 有一条边到 A,但是 A 没有边到 B,所以 B 没有出现在 A 的邻接列表中。 查找两个顶点之间的边或者权重会比较费时,因为遍历邻接列表直到找到为止。
2.领接矩阵:由二维数组对应的行和列都表示顶点,由两个顶点所决定的矩阵对应元素数值表示这里两个顶点是否相连(如, 0 表示不相连,非 0 表示相连和权值)、如果相连这个值表示的是相连边的权重。例如,广西到北京的机票, 我们用邻接矩阵表示:
往这个图中添加顶点的成本非常昂贵,因为新的矩阵结果必须重新按照新的行/列创建,然后将已有的数据复制 到新的矩阵中。
注意:大多数时候,选择邻接列表是正确的。(在图比较稀疏的情况下,每一个顶点都只会和少数几个顶点相 连,这种情况下邻接列表是最佳选择。如果这个图比较密集,每一个顶点都和大多数其他顶点相连,那么邻接 矩阵更合适。)
创建图:(以邻接列表为例)
1.结构体定义:
#define MaxSize 1024
typedef struct _EdgeNode {
//与节点连接的边的定义
int adjvex; //邻接的顶点
int weight; //权重
struct _EdgeNode *next; //下一条边
}EdgeNode;
typedef struct _VertexNode{//顶点节点
char data; //节点数据
struct _EdgeNode *first;//指向邻接第一条边
}VertexNode, AdjList;
typedef struct _AdjListGraph {
AdjList *adjlist;
int vex; //顶点数
int edge; //边数
}AdjListGraph;
2.邻接表的初始化
/*图的初始化*/
void Init(AdjListGraph &G){
G.adjlist = new AdjList[MaxSize];
G.edge = 0;
G.vex = 0;
}
3.创建图
/*通过顶点对应的字符寻找顶点在图中的邻接点*/
int Location(AdjListGraph &G, char c){
for(int i=0; i<G.vex; i++){
if(G.adjlist[i].data == c) {
return i;
}
}return -1;
}
/*图的创建*/
void Create(AdjListGraph &G){
cout << "请输入该图的顶点数以及边数:" << endl;
cin>> G.vex >> G.edge;
cout<<"请输入相关顶点:"<< endl;
for(int i=0; i<G.vex; i++){
cin >> G.adjlist[i].data;
G.adjlist[i].first = NULL;
}
char v1=0, v2=0;//保存输入的顶点的字符
int i1, i2; //保存顶点在数组中的下标
cout<<"请输入想关联边的顶点:"<< endl;
for(int i=0; i<G.edge; i++){
cin >>v1 >>v2; i1 = Location(G, v1);
i2 = Location(G, v2);
if(i1!=-1 && i2!=-1){
//寻找到位置
EdgeNode *temp = new EdgeNode;
temp->adjvex = i2;
temp->next = G.adjlist[i1].first;
G.adjlist[i1].first = temp;
}
}
}
4.邻接表的深度遍历
首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;
当没有未访问过的顶点时,则回到上一个顶点,继续试探别的顶点,直到所有的顶点都被访问过。
1. 首先从一个未走到过的顶点作为起始顶点,比如 A 顶点作为起点。
2. 沿 A 顶点的边去尝试访问其它未走到过的顶点,首先发现 E 号顶点还没有走到过,于是访问 E 顶点。
3. 再以 E 顶点作为出发点继续尝试访问其它未走到过的顶点,接下来访问 D 顶点。
4. 再尝试以 D 顶点作为出发点继续尝试访问其它未走到过的顶点。
5. 但是,此时沿 D 顶点的边,已经不能访问到其它未走到过的顶点,接下来返回到 E 顶点。
6. 返回到 E 顶点后,发现沿 E 顶点的边也不能再访问到其它未走到过的顶点。此时又回到顶点 A(D->E->A),再以 A 顶点作为出发点继续访问其它未走到过的顶点,于是接下来访问 C 顶点。
7. 最终访问的结果是 A -> E -> D -> C -> B`
/*对图上的顶点进行深度遍历*/
void DFS(AdjListGraph &G,int v){
int next = -1;
if(visited[v])
return;
cout<<G.adjlist[v].data<<" ";
visited[v] = true; //设置为已访问
EdgeNode *temp = G.adjlist[v].first;
while(temp){
next = temp->adjvex;
temp = temp->next;
if(visited[next] == false){
DFS(G, next);
}
}
}
/*对所有顶点进行深度遍历*/
void DFS_Main(AdjListGraph &G){
for(int i=0; i<G.vex; i++){
if(visited[i] == false){
DFS(G, i);
}
}
}