上一期文章分享完了图的两种遍历方式,也是两种很重要的算法——DFS和BFS。这两种算法的应用和重要性我就不多说了,内行的人懂的都懂。今天这文章重要就是来上机实现这两种算法,又由于这两种算法都可以由邻接矩阵和邻接表来表示,博主分享的代码都是上机测试过的,在vs2019(其他编译器我不知道行不行)上都是可以运行的。
1.深度优先搜索(DFS):
#include<stdio.h>
#define MAX_VERTEX_NUM 20 //最大顶点数
/*
*采用邻接表存储无向图
*无论哪种存储结构,都需要想办法来构造结构存储 顶点集和边集
*/
typedef struct
{
char vexs[MAX_VERTEX_NUM]; //一维数组存储顶点集
//int vexs[] = {1,2,3,4,5}; //根据顶点的类型来选择存储顶点的数组类型,复杂的顶点可以定义结构体来存储
int AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接表存储边集
int vexnum, arcnum; //图中顶点数和弧的数量
} MGraph;
/*定位顶点在图中的位置*/
int LocateVex(MGraph G, char vex)
{
for (int i = 0; i < G.vexnum; i++)
{
if (G.vexs[i] == vex)
return i;
}
return -1;
}
/*创建图*/
void CreateGraph(MGraph& G)
{
/*初始化图的基本信息*/
//输入图中顶点
printf("请输入图中顶点数量:");
scanf_s("%d", &G.vexnum);
for (int i = 0; i < G.vexnum; i++)
{
printf("请输入第%d个顶点:", i + 1);
scanf_s(" %c", &G.vexs[i]);
}
//输入图中的边
printf("请输入图中边的数量:");
scanf_s("%d", &G.arcnum);
//初始化邻接矩阵
for (int i = 0; i < G.vexnum; i++)
{
for (int j = 0; j < G.vexnum; j++)
{
G.AdjMatrix[i][j] = 0; //初始化时顶点间都不存在边
}
}
//构造邻接矩阵
for (int k = 0; k < G.arcnum; k++)
{
char v1, v2;
printf("请输入第%d条边(如:AB):", k + 1);
scanf_s(" %c%c", &v1, &v2);
int i = LocateVex(G, v1); //获取边第一个顶点在图中的位置
int j = LocateVex(G, v2); //获取边第二个顶点在图中的位置
G.AdjMatrix[i][j] = 1; //存在边就设置为1
G.AdjMatrix[j][i] = 1; //由于是无向图所以相反反向也存在边
}
printf("图创建成功!\n");
}
/*
*G:不为空的图
*v:需要访问的顶点
*/
void VisitFun(MGraph G, int v)
{
printf("%c ", G.vexs[v]);
}
/*
*G:不为空的图
*v:其实访问的顶点
*/
void DFS(MGraph G, int* visited, int v)
{
visited[v] = 1; //将访问的结点设置为1
//访问这个这个顶点
VisitFun(G, v);
//寻找与这个顶点相邻的其他结点
for (int k = 0; k < G.vexnum; k++)
{
if (G.AdjMatrix[v][k] == 1)
{ //有边
if (visited[k] == 0)
{
//且该顶点没有被访问过
//那么久递归调用DFS去遍历与这个边邻接的顶点
DFS(G, visited, k);
}
}
}
}
int main() {
int visited[MAX_VERTEX_NUM];
//初始化访问标记数组 顶点访问则设置为1
for (int i = 0; i < MAX_VERTEX_NUM; i++)
{
visited[i] = 0;
}
MGraph G;
CreateGraph(G);
DFS(G, visited, 0);
}
程序执行图:
2.广度优先遍历(BFS):
#include <stdio.h>
#include <stdlib.h>
//定义图的最多有20个顶点
#define MAX_VERTEX_NUM 20
struct node//定义图的顶点
{
char data;
int flag;//标志位(1:访问过 0:未访问 )
struct arcNode* firstArcNode;
};
struct arcNode
{
int no;
struct arcNode* nextArcNode;
};
struct qNode //定义队列的结构体
{
struct node* Node;
struct qNode* nextQNode;
};
struct queue
{
struct qNode* front;
struct qNode* rear;
};
void createArcNode(struct node* Node)
{
int i = 1;
int position = 0;
struct arcNode* arcNode, * temp, * temp2;
printf("请输入与顶点%c相连的顶点在数组中的位置:\n", Node->data);
printf("***输入0表示结束输入***\n");
while (1) {
printf("第%d个与顶点%c相连的顶点在数组中的位置:", i++, Node->data);
scanf_s("%d", &position);
temp = (struct arcNode*)malloc(sizeof(struct arcNode));
if (temp == NULL) {
printf("内存分配失败!");
}
if (position == 0) {
arcNode->nextArcNode = NULL;
break;
}
if (i == 2) {
temp->no = position;
Node->firstArcNode = temp;
arcNode = temp;
}
else {
temp->no = position;
arcNode->nextArcNode = temp;
arcNode = temp;
}
}
}
void rangeTraverse(struct node arrayList[], int position) {
int i;
struct queue* Queue = init();
struct node* Node;
struct arcNode* arcNode;
//把数组中的顶点全部标记为未访问:falg=0
for (i = 1; i < 20; i++) {
if (arrayList[i].data != '0') {
arrayList[i].flag = 0;
}
else {
break;
}
}
inQueue(Queue, &arrayList[position]);
arrayList[position].flag = 1;
while (isEmpty(Queue)) {
Node = outQueue(Queue);
printf("%c ", Node->data);
arcNode = Node->firstArcNode;
i = 1;
while (i) {
Node = &arrayList[arcNode->no];
if (Node->flag == 0) {
Node->flag = 1;
inQueue(Queue, Node);
}
if (arcNode->nextArcNode == NULL) {
i = 0;
}
arcNode = arcNode->nextArcNode;
}
}
}
struct queue* init() {
struct queue* Queue = (struct queue*)malloc(sizeof(struct queue));
struct qNode* QNode = (struct qNode*)malloc(sizeof(struct qNode));
if (QNode == NULL || Queue == NULL) {
printf("内存分配失败");
}
Queue->front = QNode;
Queue->rear = QNode;
return Queue;
}
void inQueue(struct queue* Queue, struct node* Node) {
struct qNode* QNode = (struct qNode*)malloc(sizeof(struct qNode));
if (QNode == NULL) {
printf("内存分配失败");
}
QNode->Node = Node;
QNode->nextQNode = NULL;//队尾元素,指针为空
Queue->rear->nextQNode = QNode;
Queue->rear = QNode;
}
struct node* outQueue(struct queue* Queue) {
struct node* Node;
struct qNode* QNode;
if (Queue->front == Queue->rear) {
printf("队列已空!");
}
QNode = Queue->front->nextQNode;
Node = QNode->Node;
Queue->front->nextQNode = QNode->nextQNode;
//当队列中最后一个元素被删除后,队列尾指针也丢失了,因此需要对队尾指针重新赋值
if (Queue->rear == QNode) {
Queue->rear = Queue->front;
}
return Node;
}
int isEmpty(struct queue* Queue) {
if (Queue->front == Queue->rear) {
return 0;
}
return 1;
}
int main(int argc, char* argv[])
{
struct node arrayList[MAX_VERTEX_NUM];
char ch;
int flag = 1;//标志位,0表示输入结束
int position = 1;
struct arcNode* testNode;//测试用弧点
printf("输入顶点信息(顶点信息用一个字符表示):\n");
printf("***输入0表示结束输入***\n");
while (1) {
printf("第%d个顶点的信息为:", position);
scanf_s(" %c", &arrayList[position].data);//在%c之前加空格解决把回车符当做输入字符的问题
if (arrayList[position].data == '0') {
break;
}
position += 1;
}
for (flag = 1; flag < 20; flag++) {
if (arrayList[flag].data != '0') {
printf("\n");
createArcNode(&arrayList[flag]);
}
else {
break;
}
}
//输出邻接表
for (flag = 1; flag < 20; flag++) {
if (arrayList[flag].data != '0') {
printf("\n");
testNode = arrayList[flag].firstArcNode;
printf("%d %c :", flag, arrayList[flag].data);
while (1) {
printf("%d ", testNode->no);
if (testNode->nextArcNode == NULL) {
break;
}
testNode = testNode->nextArcNode;
}
}
else {
break;
}
}
printf("\n");
printf("图建立完毕,按1进行广度优先遍历:");
scanf_s("%d", &position);
if (position == 1) {
while (1) {
printf("\n");
printf("输入开始节点在数组中的位置:");
scanf_s("%d", &position);
rangeTraverse(arrayList, position);
}
}
system("PAUSE");
return 0;
}
好啦,关于图的两种遍历方式的C语言实现版就到这啦,如果有能力的同学也可以试着用其他语言写一下。
本贴为博主亲手整理。如有错误,请评论区指出,一起进步。谢谢大家的浏览.