有一幅图:
图的“顶点”为:1,2,3,4,5,6,7,8
用下面三个结构体表示图的邻接表存储信息:
//“结点”结构体,存储与“顶点”相连的顶点
typedef struct node
{
int adjVex; //“顶点”对应的“结点”信息
struct node *next; //指向下一个与“某顶点”相连的结点
}EdgeNode;
//顶点结构体
typedef struct vnode
{
char vertex; //顶点信息
EdgeNode *firstEdge; //指向第一个与“此顶点”相连的结点
}AdjList;
//图结构体
typedef struct
{
AdjList vertexs[VERTEXNUM]; //邻接表,即顶点数组
int verNum, edgeNum; //图中当前的顶点和边数
}Graph;
顶点1对应的顶点(结点)为2,3,所以“顶点1的表”构造步骤:
1->NULL //1初始指向的结点位置NULL
1->2->NULL //2指向1指向的结点位置NULL,1指向2
1->3->2->NULL //3指向1指向的结点位置2,1指向3
剩余顶点表构造步骤相同:
2->5->4->1->NULL
3->7->6->1->NULL
4->8->2->NULL
5->8->2->NULL
6->7->3->NULL
7->6->3->NULL
8->5->4->NULL
注意:边的输入顺序会影响邻接表存储顺序(1->3->2->NULL也可以是1->2->3->NULL),进而影响遍历结果输出。
下面代码实现为图的邻接表构造与搜索:
#include <cstdio>
#include <cstdlib>
#include <queue>
using namespace std;
#define VERTEXNUM 8 //顶点个数
#define DONE 1 //visitedV
#define UNDONE 0
bool visitedV[VERTEXNUM];
//结点结构体
typedef struct node
{
int adjVex; //顶点对应的结点信息
struct node *next; //指向下一条边的指针
}EdgeNode;
//顶点结构体
typedef struct vnode
{
char vertex; //顶点信息
EdgeNode *firstEdge; //指向第一条依附该顶点的边的指针
}AdjList;
//图结构体
typedef struct
{
AdjList vertexs[VERTEXNUM]; //邻接表
int verNum, edgeNum; //图中当前的顶点和边数
}Graph;
void MakeGraph(Graph *graph)
{
int i, j;
printf("请输入图的顶点数n和边数e:\n");
//scanf("%d%d", &graph->verNum, &graph->edgeNum);
graph->verNum = 8;
graph->edgeNum = 18;
printf("请输入顶点信息(顶点号<CR>)每个顶点以回车作为结束:\n");
/*
for(i = 0; i < graph->verNum; i++)
{
getchar();
scanf("%c", &graph->vertexs[i].vertex);
graph->vertexs[i].firstEdge = NULL; //初始第一条边为空
}
*/
//char my_vertexs[8] = {'a','b','c','d','e','f','g','h'};
char my_vertexs[8] = {'1','2','3','4','5','6','7','8'};
for(int x = 0; x<8; x++)
{
graph->vertexs[x].vertex = my_vertexs[x];
graph->vertexs[x].firstEdge = NULL;
}
printf("请输入每条边对应的两个顶点的序号(格式为i,j):\n");
//1,2 1,3 2,1 2,4 2,5 3,1 3,6 3,7 4,2
//4,8 5,2 5,8 6,3 6,7 7,3 7,6 8,4 8,5
int a[18] = {1,1,2,2,2,3,3,3,4,4,5,5,6,6,7,7,8,8};
int b[18] = {2,3,1,4,5,1,6,7,2,8,2,8,3,7,3,6,4,5};
EdgeNode *p;
for(int k = 0; k < graph->edgeNum; k++)
{
//scanf("%d,%d", &i, &j); //读入边<vi,vj>的序号
i = a[k];
j = b[k];
p = (node *)malloc(sizeof(node)); //生成新的结点
p->adjVex = j - 1; //顶点对应的结点信息(也是顶点);因为用的是数组,数组下标减1
//结点指向顶点指向的位置;(最初顶点指向NULL,所以第1个结点就指向空;下一行代码中,顶点指向第1个结点;
//来了第2个结点,第2个结点便指向第1个结点,而后下一行代码中,顶点指向第2个结点)
p->next = graph->vertexs[i - 1].firstEdge;
graph->vertexs[i - 1].firstEdge = p;//顶点指向结点;
}
}
void DFSTraverse(Graph *graph, int v)
{
visitedV[v] = DONE;
printf("深度遍历:结点%c\n", graph->vertexs[v].vertex);
EdgeNode *p = graph->vertexs[v].firstEdge;
while(p != NULL)
{
if(!visitedV[p->adjVex])
DFSTraverse(graph, p->adjVex);
p = p->next;
}
}
void DFS(Graph *graph)
{
int i;
for(i = 0; i < graph->verNum; i++)
visitedV[i] = UNDONE;
for(i = 0; i < graph->verNum; i++)
if(!visitedV[i])
DFSTraverse(graph, i);
}
void BFS(Graph *graph)
{
int i, j, k;
queue<int> q;
EdgeNode *p;
for(i = 0; i < graph->verNum; i++) //初始化访问标识数组
visitedV[i] = UNDONE;
for(i = 0; i < graph->verNum; i++)
{
if(!visitedV[i])
{
visitedV[i] = DONE;
printf("广度优先遍历:结点%c\n", graph->vertexs[i].vertex);
q.push(i); //入栈
while(!q.empty())
{
j = q.front();
q.pop(); //出栈
p = graph->vertexs[j].firstEdge;
while(p)
{
if(!visitedV[p->adjVex])
{
printf("广度优先遍历:结点%c\n", graph->vertexs[p->adjVex].vertex);
visitedV[p->adjVex] = DONE;
q.push(p->adjVex);
}
p = p->next;
}
}
}
}
}
int main()
{
Graph *graph = (Graph *)malloc(sizeof(Graph));
MakeGraph(graph); //建立图的邻接表
//DFS(graph); //深度优先遍历
BFS(graph); //广度优先遍历
return 0;
}