目录
算法核心:
实验课题:![](https://img-blog.csdnimg.cn/f859e52a0a764b5f8e124b4ac5966263.jpeg)
现有一组无向图,要求用DFS和BFS遍历图,依次输出相关值。
实验代码(C):
实验思路:
采用读取text文件,第一阶段依次读取文件中的顶点表数量和边表的数量,第二阶段读取各个顶点的名称,第三阶段读取各边表的两个下标位置。(注意:若是构建有向图的,可以在赋予边表时候只赋给一边,本案例是按照无向图双边赋值)。
实验代码解释:
申明相关变量:
申明变量(链表、节点、队列)
#include<stdio.h>
#include<stdlib.h>
//#include<malloc.h>
#define _CRT_SECURE_NO_WARNINGS
#define MaxVertices 100
#define MaxVertNum 100
#define MAX 10
typedef int VertextType;//顶点类型应由用户定义
//typedef int EdgeType;//边上的权值类型应由用户定义
/*边表结点*/
typedef struct EdgeNode {//边表结点 边表
int adjvex;//邻接点域,存储该顶点对应的下标
//EdgeType weight;//用于存储权值,对于非网图可以不需要
struct EdgeNode* next;//链域,指向下一个邻接点
}EdgeNode;
typedef struct VertextNode {//顶点表结点 顶点表
VertextType data;//顶点域,存储顶点信息
EdgeNode* firstedge;//边表头指针
}VertexNode;
typedef VertexNode AdjList[MaxVertices];//顶点表数组
typedef struct {
//VertexNode adjList[MaxVertices];
AdjList adjList;//存放所有顶点表的数组-> VertexNode adjList[MaxVertices]
int numVertexes, numEdges;//图中当前顶点数和边数
}GraphAdjList;
typedef GraphAdjList* GraphAdj;
typedef struct LoopQueue{ //定义循环队列结构体
int data[MAX];
int front;
int rear; //注意每次队尾标记指向最后一个元素的下一个位置
}Queue, *LQueue;
void InitQueue(LQueue &Q){ //初始化队列
Q->front = Q->rear = 0;
}
bool QueueisFull(LQueue &Q){ //判断队列是否满了
if((Q->rear + 1) % MAX == Q->front){
return true; //已满
}
else{
return false;
}
}
bool QueueisEmpty(LQueue &Q){//判断队列是否为空
if(Q->front == Q->rear){
return true;
}
return false;
}
void EnQueue(LQueue &Q, int i){ //入队列
if(!QueueisFull(Q)){
Q->data[Q->rear] = i;
Q->rear = (Q->rear + 1) % MAX; //队尾指针后移
}
}
void DeQueue(LQueue &Q, int *k){ //出队列
if(!QueueisEmpty(Q)){
*k = Q->data[Q->front];
Q->front = (Q->front + 1) % MAX;
}
}
初始化数据
int InitGraph(GraphAdj G) {
int i, j;
EdgeNode* s;//新的边结点
FILE* fp = NULL;
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList2.txt", "rb");
if (fp == NULL) {
printf("ERROR");
return -1;
}
fscanf(fp, "%d %d", &G->numVertexes, &G->numEdges);//顶点数,边数
/*******************创建顶点表**************************/
for (i = 0; i < G->numVertexes; i++) {
fscanf(fp, "%d", &G->adjList[i].data);
G->adjList[i].firstedge = NULL;//注意将边表置空
}
/******************创建边表****************************/
for (int k = 0; k < G->numEdges; k++) {
fscanf(fp, "%d %d", &i, &j);//"输入边(Vi,Vj)上的顶点序号
//对于直接相连的进行编入(即对输入“0 1”时,在0对应的边表中编入1)
s = (EdgeNode*)malloc(sizeof(EdgeNode));
s->adjvex = j;//边表赋值
s->next = G->adjList[i].firstedge;
G->adjList[i].firstedge = s;
//对于间接相连的进行编入(即对输入“0 1”时,在1对应的边表中编入0)
s = (EdgeNode*)malloc(sizeof(EdgeNode));
s->adjvex = i;
s->next = G->adjList[j].firstedge;
G->adjList[j].firstedge = s;
}
fclose(fp);
}
void DisplayGraph(GraphAdjList* G) {
int i;
FILE *fp;
/**文档输出 ***/
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result.txt", "w");
if (fp == NULL) {
printf("ERROR");
// return -1;
}
fprintf(fp, "Enter contents to store in file : \n");
EdgeNode* p;
for (int i = 0; i < G->numVertexes; i++) {
p = G->adjList[i].firstedge;
printf("%d->", i);
fprintf(fp, "%d->", i);
while (1) {
if (p == NULL) {
printf("^");
fprintf(fp, "^");
break;
}
printf("%d->", p->adjvex);//输出边表的下标,但这里可以表示原有的 数
fprintf(fp, "%d->", p->adjvex);
p = p->next;
}
printf("\n");
fprintf(fp, "\n");
}
fclose(fp);//???
}
主函数部分:
int main() {
int index, flage = 1;
GraphAdjList* G = (GraphAdjList*)malloc(sizeof(GraphAdjList));
InitGraph(G);
printf("现有无向图的链表存储:\n");
DisplayGraph(G);
while (flage) {
printf("现有无向图的DFS(按1):\n");
printf("现有无向图的BFS(按2):\n");
printf("退出遍历(按3):\n");
//DFSTraverse(G);
scanf("%d", &index);
switch (index) {
case 1:
DFS(G, 0);
break;
case 2:
BFS(G,0);
break;
case 3:
flage = 0;
break;
}
}
return 0;
}
算法核心:
DFS部分。运用栈。将head后面依次放入栈中,并选取栈头的visit为1置为新的head,遍历其后面的依次放入栈中,直到栈为空结束。
void DFS(GraphAdjList* G, int v0) { //图,下标位置
int stack[MaxVertNum];
EdgeNode* p;
int visited[MaxVertNum] = { 0 }, top = -1, v;
printf("此图的DFS遍历:\n");
//p = G->adjList[v0].firstedge;
stack[++top] = v0;//top=0,存储第一个数v0(下标)
FILE *fp; /**文档输出 ***/
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_DFS.txt", "w");
if (fp == NULL) {
printf("ERROR");
// return -1;
}
fprintf(fp, "此图的DFS遍历:\n");
while (top != -1)//判断栈有无有空
{
v = stack[top--];//出栈 v(数值data/下标)
if (!visited[v]) {//v 未被访问
printf("%d ", G->adjList[v].data);
fprintf(fp, "%d ", G->adjList[v].data);
visited[v] = 1;
}
p = G->adjList[v].firstedge;//边结点指针
while (p) {
if (!visited[p->adjvex]) {//p边结点的下标有无访问到
stack[++top] = p->adjvex;
}
p = p->next;
}
}
fclose(fp);
printf("\n");
}
BFS部分。运用队列。将head后面依次放入队列中,并选取队头的取出,其visit为1置为新的head,遍历其后面的依次放入队列中,直到队列为空结束。
void BFS(GraphAdjList* G,int i){
int visited[MaxVertNum] = { 0 };
//int i = 0;
Queue *Q =(LQueue)malloc(sizeof(Queue));
for(int i = 0; i < G->numVertexes; i++){
visited[i] = 0;
}
FILE *fp; /**文档输出 ***/
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_BFS.txt", "w");
if (fp == NULL) {
printf("ERROR");
// return -1;
}
fprintf(fp, "此图的BFS遍历:\n");
InitQueue(Q); //初始化队列
visited[i] = 1;//从0下标开始
printf("%d ", G->adjList[i].data);
fprintf(fp,"%d ", G->adjList[i].data);
EnQueue(Q, i);//入队?
while(!QueueisEmpty(Q)){//根据队列遍历全部顶点坐标
DeQueue(Q, &i); //这里不断的修改i的值,队头元素出队,改变i值?
EdgeNode *e = G->adjList[i].firstedge; //i顶点的邻接链表的第一个结点
while(e){//e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点
if(!visited[e->adjvex]){ // adjvex是e所表示的结点下标
visited[e->adjvex] = 1;
printf("%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
fprintf(fp,"%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
EnQueue(Q, e->adjvex); //将该结点入队
}
e = e->next; //遍历i的下一个邻接点
}
}
printf("\n");
fclose(fp);
}
实验代码(全):
#include<stdio.h>
#include<stdlib.h>
//#include<malloc.h>
#define _CRT_SECURE_NO_WARNINGS
#define MaxVertices 100
#define MaxVertNum 100
#define MAX 10
typedef int VertextType;//顶点类型应由用户定义
//typedef int EdgeType;//边上的权值类型应由用户定义
/*边表结点*/
typedef struct EdgeNode {//边表结点 边表
int adjvex;//邻接点域,存储该顶点对应的下标
//EdgeType weight;//用于存储权值,对于非网图可以不需要
struct EdgeNode* next;//链域,指向下一个邻接点
}EdgeNode;
typedef struct VertextNode {//顶点表结点 顶点表
VertextType data;//顶点域,存储顶点信息
EdgeNode* firstedge;//边表头指针
}VertexNode;
typedef VertexNode AdjList[MaxVertices];//顶点表数组
typedef struct {
//VertexNode adjList[MaxVertices];
AdjList adjList;//存放所有顶点表的数组-> VertexNode adjList[MaxVertices]
int numVertexes, numEdges;//图中当前顶点数和边数
}GraphAdjList;
typedef GraphAdjList* GraphAdj;
int InitGraph(GraphAdj G) {
int i, j;
EdgeNode* s;//新的边结点
FILE* fp = NULL;
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList2.txt", "rb");
if (fp == NULL) {
printf("ERROR");
return -1;
}
fscanf(fp, "%d %d", &G->numVertexes, &G->numEdges);//顶点数,边数
/*******************创建顶点表**************************/
for (i = 0; i < G->numVertexes; i++) {
fscanf(fp, "%d", &G->adjList[i].data);
G->adjList[i].firstedge = NULL;//注意将边表置空
}
/******************创建边表****************************/
for (int k = 0; k < G->numEdges; k++) {
fscanf(fp, "%d %d", &i, &j);//"输入边(Vi,Vj)上的顶点序号
//对于直接相连的进行编入(即对输入“0 1”时,在0对应的边表中编入1)
s = (EdgeNode*)malloc(sizeof(EdgeNode));
s->adjvex = j;//边表赋值
s->next = G->adjList[i].firstedge;
G->adjList[i].firstedge = s;
//对于间接相连的进行编入(即对输入“0 1”时,在1对应的边表中编入0)
s = (EdgeNode*)malloc(sizeof(EdgeNode));
s->adjvex = i;
s->next = G->adjList[j].firstedge;
G->adjList[j].firstedge = s;
}
fclose(fp);
}
void DisplayGraph(GraphAdjList* G) {
int i;
FILE *fp;
/**文档输出 ***/
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result.txt", "w");
if (fp == NULL) {
printf("ERROR");
// return -1;
}
fprintf(fp, "Enter contents to store in file : \n");
EdgeNode* p;
for (int i = 0; i < G->numVertexes; i++) {
p = G->adjList[i].firstedge;
printf("%d->", i);
fprintf(fp, "%d->", i);
while (1) {
if (p == NULL) {
printf("^");
fprintf(fp, "^");
break;
}
printf("%d->", p->adjvex);//输出边表的下标,但这里可以表示原有的 数
fprintf(fp, "%d->", p->adjvex);
p = p->next;
}
printf("\n");
fprintf(fp, "\n");
}
fclose(fp);//???
}
void DFS(GraphAdjList* G, int v0); //图,下标位置
void BFS(GraphAdjList* G,int v0);
int main() {
int index, flage = 1;
GraphAdjList* G = (GraphAdjList*)malloc(sizeof(GraphAdjList));
InitGraph(G);
printf("现有无向图的链表存储:\n");
DisplayGraph(G);
while (flage) {
printf("现有无向图的DFS(按1):\n");
printf("现有无向图的BFS(按2):\n");
printf("退出遍历(按3):\n");
//DFSTraverse(G);
scanf("%d", &index);
switch (index) {
case 1:
DFS(G, 0);
break;
case 2:
BFS(G,0);
break;
case 3:
flage = 0;
break;
}
}
return 0;
}
/********************DFS*************************************/
void DFS(GraphAdjList* G, int v0) { //图,下标位置
int stack[MaxVertNum];
EdgeNode* p;
int visited[MaxVertNum] = { 0 }, top = -1, v;
printf("此图的DFS遍历:\n");
//p = G->adjList[v0].firstedge;
stack[++top] = v0;//top=0,存储第一个数v0(下标)
FILE *fp; /**文档输出 ***/
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_DFS.txt", "w");
if (fp == NULL) {
printf("ERROR");
// return -1;
}
fprintf(fp, "此图的DFS遍历:\n");
while (top != -1)//判断栈有无有空
{
v = stack[top--];//出栈 v(数值data/下标)
if (!visited[v]) {//v 未被访问
printf("%d ", G->adjList[v].data);
fprintf(fp, "%d ", G->adjList[v].data);
visited[v] = 1;
}
p = G->adjList[v].firstedge;//边结点指针
while (p) {
if (!visited[p->adjvex]) {//p边结点的下标有无访问到
stack[++top] = p->adjvex;
}
p = p->next;
}
}
fclose(fp);
printf("\n");
}
/********************BFS*************************************/
typedef struct LoopQueue{ //定义循环队列结构体
int data[MAX];
int front;
int rear; //注意每次队尾标记指向最后一个元素的下一个位置
}Queue, *LQueue;
void InitQueue(LQueue &Q){ //初始化队列
Q->front = Q->rear = 0;
}
bool QueueisFull(LQueue &Q){ //判断队列是否满了
if((Q->rear + 1) % MAX == Q->front){
return true; //已满
}
else{
return false;
}
}
bool QueueisEmpty(LQueue &Q){//判断队列是否为空
if(Q->front == Q->rear){
return true;
}
return false;
}
void EnQueue(LQueue &Q, int i){ //入队列
if(!QueueisFull(Q)){
Q->data[Q->rear] = i;
Q->rear = (Q->rear + 1) % MAX; //队尾指针后移
}
}
void DeQueue(LQueue &Q, int *k){ //出队列
if(!QueueisEmpty(Q)){
*k = Q->data[Q->front];
Q->front = (Q->front + 1) % MAX;
}
}
void BFS(GraphAdjList* G,int i){
int visited[MaxVertNum] = { 0 };
//int i = 0;
Queue *Q =(LQueue)malloc(sizeof(Queue));
for(int i = 0; i < G->numVertexes; i++){
visited[i] = 0;
}
FILE *fp; /**文档输出 ***/
fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_BFS.txt", "w");
if (fp == NULL) {
printf("ERROR");
// return -1;
}
fprintf(fp, "此图的BFS遍历:\n");
InitQueue(Q); //初始化队列
visited[i] = 1;//从0下标开始
printf("%d ", G->adjList[i].data);
fprintf(fp,"%d ", G->adjList[i].data);
EnQueue(Q, i);//入队?
while(!QueueisEmpty(Q)){//根据队列遍历全部顶点坐标
DeQueue(Q, &i); //这里不断的修改i的值,队头元素出队,改变i值?
EdgeNode *e = G->adjList[i].firstedge; //i顶点的邻接链表的第一个结点
while(e){//e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点
if(!visited[e->adjvex]){ // adjvex是e所表示的结点下标
visited[e->adjvex] = 1;
printf("%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
fprintf(fp,"%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
EnQueue(Q, e->adjvex); //将该结点入队
}
e = e->next; //遍历i的下一个邻接点
}
}
printf("\n");
fclose(fp);
}
实验效果: