实验题目:
“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”
也就是在无向图中,以节点作为人,两个节点之间的路径小于等于6。
实验要求
求出与一个节点满足上述要求的其他节点的数目,初始值为1
如图 以A, B为例
A: 没有与A满足上述条件的点.因此。A节点的值为0
B: D C E H G F都满足条件 因此B节点的值就是7
实验思路:
即无向图的广度优先遍历
1.图的存储
书上讲过无向图的存储最好是邻接多重链表,但是看起来比较麻烦,我就偷懒用了邻接表来存储
创建方式,定义表头节点和表节点
typedef struct EdgeNode
{
int adjvex;
struct EdgeNode * next;
} EdgeNode;
//顶点表节点结构,tag用来判定是否被遍历过,一个firstedge是用来指向边表的第一个节点
typedef struct
{
int tag;
EdgeNode * firstedge;
} AdjList;
定义表头节点的数组,表的初始化就完成了。
存储图,忽略节点名字,以数组下标代替节点名。tag初始为0,输入一条边的头尾节点,在头尾节点对应的表头节点后加入信息。
实现代码
void add(int x, int y)
{
if (adjList[x - 1].firstedge == NULL)
{
EdgeNode *p;
p = new EdgeNode;
p->adjvex = y - 1;
p->next = NULL;
adjList[x - 1].firstedge = p;
}
else {
EdgeNode *p , *q;
p = adjList[x - 1].firstedge;
while (p->next)
{
p = p->next;
}
q = new EdgeNode;
q->adjvex = y - 1;
q->next = NULL;
p->next = q;
}
// 无向图,一条边对应两个结点
if (adjList[y - 1].firstedge == NULL)
{
EdgeNode *p;
p = new EdgeNode;
p->adjvex = x - 1;
p->next = NULL;
adjList[y - 1].firstedge = p;
}
else {
EdgeNode *p, *q;
p = adjList[y - 1].firstedge;
while (p->next)
{
p = p->next;
}
q = new EdgeNode;
q->adjvex = x - 1;
q->next = NULL;
p->next = q;
}
}
2.图的广度优先遍历
在上述存储结构的前提下,以每个节点为初始节点,依次进行广度优先遍历
思路:定义两个队列,用来存储本次访问节点的下标和下次访问节点的下标,以便于计算路径长度。在本次访问节点队列不空的情况下,再次进行循环,直到空为止,循环第一次结束。依次类推
下面以图的形式具体说明
第一次以0下标开始,tag置为1,表示被访问过。本次队列和下次队列都为null
首先进行本次队列赋值,此时路径为1
之后再本次队列不为空并且路径小于6的前提下进行另一个循环
①以本次队列中的数据作为起始位置,若遍历的节点中,tag为0,则该节点进入下次队列,直到本次队列空为止。此时数据的状态为
此时将下次队列的值赋给本次队列,此时路径变为2
继续进行循环①
①循环结束之后 将所有tag置为0,队列清空进行以下一个节点为初始节点的计算,重复上述过程直到循环结束
实现代码
void BL(int x)
{
// 数组下标对应到存储改序号节点路径不超过6的节点个数
double num[10];
for (int i = 0; i < x; i++)
{
num[i] = 1;
}
queue<int>q;
queue<int>r;
for (int i = 0; i < num_vertex; i++)
{
// 从第一个节点开始,依次广度遍历图,k为当前节点到各节点的路径长度
int k = 0;
EdgeNode *p;
// 记录是否访问过该点
adjList[i].tag = 1;
p = adjList[i].firstedge;
// 记录路径长度为1的节点个数
while (p) {
if (adjList[p->adjvex].tag == 0)
{
num[i]++;
adjList[p->adjvex].tag = 1;
q.push(p->adjvex);
}
if (!p->next)
{
break;
}
if (p->next)
{
p = p->next;
}
}
k++;
// 记录路径长度为2~6的节点个数,q队列中存入本次次广度遍历的节点,r队列存入下一次广度
// 遍历的节点。来区分不同的路径长度
while (!q.empty() && k < 6)
{
p = adjList[q.front()].firstedge;
q.pop();
while (p) {
if (adjList[p->adjvex].tag == 0)
{
num[i]++;
adjList[p->adjvex].tag = 1;
r.push(p->adjvex);
}
if (!p->next)
{
break;
}
else p = p->next;
}
if (q.empty() && !r.empty())
{
while (!r.empty())
{
q.push(r.front());
r.pop();
}
k++;
}
}
// 初始化数据,准备进行从下一个节点开始的广度遍历
for (int j = 0; j < num_vertex; j++)
{
adjList[j].tag = 0;
}
while (!q.empty())
{
q.pop();
}
while (!r.empty())
{
r.pop();
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。