数据结构 图的遍历(广度优先遍历、深度优先遍历)
8.6、图的广度优先遍历
- 找到与顶点相邻的所有顶点,
- 标记哪些顶点被访问过
- 需要一个辅助队列
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define MaxSize 100
#define boolean int
#define true 1
#define false 0
//邻接矩阵存储图的信息
typedef struct MGraph{
char Vex[MaxSize];//顶点信息
int Edge[MaxSize][MaxSize];//邻接矩阵
int vexnum,arcnum;//顶点数和边数
}MGraph;
//初始化一个邻接矩阵
boolean MG_Init(MGraph **G){
*G = (MGraph*)malloc(sizeof(MGraph));
if((*G) == NULL) return false;//申请空间失败
(*G)->vexnum = 0;//顶点数为0
(*G)->arcnum = 0;//边数为0
// for(int i = 0;i < MaxSize;i++){
// for(int j = 0;j < MaxSize;j++){
// (*G)->Edge[i][j] = 0;
// }
// }
return true;
}
//获取该结点v的索引
int GetV_Index(MGraph *G,char v){
for(int i = 0;i<G->vexnum;i++){
if(G->Vex[i] == v) return i;
}
return -1;
}
//判断图中是否有结点v
boolean IsVEmpty(MGraph *G,char v){
for(int i=0;i<G->vexnum;i++){
if(G->Vex[i] == v) return true;//存在
}
return false;//不存在
}
//判断图中是否存在该边;传入边
boolean Adjancent(MGraph *G,char v,char w){
int vi = GetV_Index(G,v);
int wi = GetV_Index(G,w);
return G->Edge[vi][wi];
}
//判断图中是否存在该边;传入边的索引
boolean Adjancent1(MGraph *G,int vi,int wi){
if(G->Edge[vi][wi] == 1) return true;
else return false;
}
//插入一个新的顶点
boolean InsertV(MGraph *G,char v){
if(G->vexnum >= MaxSize || IsVEmpty(G,v)){
printf("存储顶点数的空间满了或者改结点存在!\n");
return false;
}
G->Vex[G->vexnum++] = v;
return true;
}
//插入边(v,w)
boolean AddEdge(MGraph *G,char v,char w){
if(!IsVEmpty(G,v) || !IsVEmpty(G,w)){
printf("输入的边其中有一个顶点或者两个顶点不存在\n");
return false;
}
//获取结点的索引
int vi = GetV_Index(G,v);
int wi = GetV_Index(G,w);
if(Adjancent1(G,vi,wi)){
printf("该边已经存在\n");
return false;
}
//修改邻接矩阵
G->Edge[vi][wi] = 1;
G->Edge[wi][vi] = 1;
//修改边数
G->arcnum++;
return true;
}
//删除边(v,w)
boolean RemoveEdge(MGraph *G,char v,char w){
if(!IsVEmpty(G,v) || !IsVEmpty(G,w)){
//判断这两个点是否存在
printf("这两个点不存在\n");
return false;
}
int vi = GetV_Index(G,v);
int wi = GetV_Index(G,w);
if(Adjancent1(G,vi,wi) == true){//存在该边就删除
G->Edge[vi][wi] = 0;
G->Edge[wi][vi] = 0;
G->arcnum--;//边减1
return true;
}else{
printf("删除的边不存在\n");
return false;
}
}
//获取某个结点v的所有邻接边
boolean NeighBors(MGraph *G,char v,char ***res,int *length){
if(!IsVEmpty(G,v)){
printf("输入的顶点不存在\n");
return false;
}
int vi = GetV_Index(G,v);
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[vi][i] == 1) {
(*length)++;
}
}
*res = (char **)malloc(sizeof(char)*(*length));
int index = 0;
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[vi][i] == 1) {
(*res)[index] = (char *)malloc(sizeof(char)*2);
(*res)[index][0] = v;
(*res)[index][1] = G->Vex[i];
index++;
}
}
return true;
}
//队列的数据信息
typedef struct ElemType{
int index;
char v;
}ElemType;
//结点
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
}LinkNode;
//链队列定义
typedef struct{
LinkNode *front,*rear;//*front 队头指针, *rear 队尾指针
}LinkQueue;
//初始化带头结点的队列
int InitLinkQueue(LinkQueue *Q){
(*Q).front = (*Q).rear = (LinkNode *)malloc(sizeof(LinkNode));
if((*Q).front == NULL || (*Q).rear == NULL) return false;
(*Q).front->next = NULL;
return true;
};
//带头结点判断是否为空
int IsEmpty(LinkQueue Q){
if(Q.front == Q.rear) return true;
else return false;
}
//带头结点入队操作
int EnQueue(LinkQueue *Q,ElemType e){
LinkNode *p = (LinkNode *)malloc(sizeof(LinkNode));
if(p==NULL) return false;//分配内存失败
p->data = e;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
}
//带头结点出队操作
int DeQueue(LinkQueue *Q,ElemType *e){
if(Q->front == Q->rear) return false;//队列为空,出队失败
LinkNode *p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
if(Q->rear == p){ //如果出队的元素是对尾元素,需要特殊处理
Q->rear = Q->front;
}
free(p);//释放片
return true;
}
//寻找某个结点V的所有邻接点
boolean Neighbors(MGraph *G,char V,int Vi,char **resNode,int **resIndex,int *length){
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[Vi][i] == 1){
(*length)++;
}
}
*resNode = (char *)malloc(sizeof(char)*(*length));
*resIndex = (int *)malloc(sizeof(int)*(*length));
int index = 0;
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[Vi][i] == 1){
(*resNode)[index] = G->Vex[i];
(*resIndex)[index] = i;
index++;
}
}
return true;
}
//广度优先遍历
void BFS(MGraph *G,char V,int Vi,char **res,int *resLength,boolean **visited){
LinkQueue Q;
InitLinkQueue(&Q);
ElemType e;
e.index = Vi;
e.v = V;
(*visited)[Vi] = true;
EnQueue(&Q,e);
while(!IsEmpty(Q)){
DeQueue(&Q,&e);
(*res)[*resLength] = e.v;
(*resLength)++;
char *resChar;
int *resIndex;
int length = 0;
Neighbors(G,e.v,e.index,&resChar,&resIndex,&length);
for(int i = 0;i < length;i++){
if((*visited)[resIndex[i]] == false){
(*visited)[resIndex[i]] = true;
ElemType e1;
e1.index = resIndex[i];
e1.v = resChar[i];
EnQueue(&Q,e1);
}
}
}
}
//访问结点
void visitV(char *res,int resLength){
for(int i = 0;i < resLength;i++){
printf("%c ,",res[i]);
}
}
//对图G进行广度优先遍历
void BFSMGraph(MGraph *G,char V){
int Vi = GetV_Index(G,V);
char *res = (char *)malloc(sizeof(char)*G->vexnum);
int resLength = 0;
boolean *visited = (boolean *)malloc(sizeof(boolean)*G->vexnum);
for(int i = 0;i < G->vexnum;i++){
visited[i] = false;
}
BFS(G,'A',Vi,&res,&resLength,&visited);
for(int i = 0;i < G->vexnum;i++){
if(visited[i] == false){
BFS(G,G->Vex[i],i,&res,&resLength,&visited);
}
}
visitV(res,resLength);
}
int main(){
MGraph *G;
MG_Init(&G);
printf("顶点数:%d;边数:%d\n",G->vexnum,G->arcnum);
InsertV(G,'A');
InsertV(G,'B');
InsertV(G,'C');
InsertV(G,'D');
InsertV(G,'E');
InsertV(G,'F');
InsertV(G,'G');
InsertV(G,'H');
InsertV(G,'I');
InsertV(G,'J');
InsertV(G,'K');
printf("顶点数:%d;边数:%d\n",G->vexnum,G->arcnum);
AddEdge(G,'A','B');
AddEdge(G,'A','C');
AddEdge(G,'C','D');
AddEdge(G,'D','E');
AddEdge(G,'D','F');
AddEdge(G,'E','F');
AddEdge(G,'E','G');
AddEdge(G,'F','G');
AddEdge(G,'F','H');
AddEdge(G,'G','H');
AddEdge(G,'I','J');
AddEdge(G,'J','K');
AddEdge(G,'I','K');
printf("顶点数:%d;边数:%d\n",G->vexnum,G->arcnum);
BFSMGraph(G,'A');
return 0;
}
//结果:
顶点数:0;边数:0
顶点数:11;边数:0
顶点数:11;边数:13
A ,B ,C ,D ,E ,F ,G ,H ,I ,J ,K ,
广度生成树
8.7、图的深度优先遍历
沿着一条路径往里面找,直到找不到结点才返回
使用递归的思想来完成
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define MaxSize 100
#define boolean int
#define true 1
#define false 0
//邻接矩阵存储图的信息
typedef struct MGraph{
char Vex[MaxSize];//顶点信息
int Edge[MaxSize][MaxSize];//邻接矩阵
int vexnum,arcnum;//顶点数和边数
}MGraph;
//初始化一个邻接矩阵
boolean MG_Init(MGraph **G){
*G = (MGraph*)malloc(sizeof(MGraph));
if((*G) == NULL) return false;//申请空间失败
(*G)->vexnum = 0;//顶点数为0
(*G)->arcnum = 0;//边数为0
// for(int i = 0;i < MaxSize;i++){
// for(int j = 0;j < MaxSize;j++){
// (*G)->Edge[i][j] = 0;
// }
// }
return true;
}
//获取该结点v的索引
int GetV_Index(MGraph *G,char v){
for(int i = 0;i<G->vexnum;i++){
if(G->Vex[i] == v) return i;
}
return -1;
}
//判断图中是否有结点v
boolean IsVEmpty(MGraph *G,char v){
for(int i=0;i<G->vexnum;i++){
if(G->Vex[i] == v) return true;//存在
}
return false;//不存在
}
//判断图中是否存在该边;传入边
boolean Adjancent(MGraph *G,char v,char w){
int vi = GetV_Index(G,v);
int wi = GetV_Index(G,w);
return G->Edge[vi][wi];
}
//判断图中是否存在该边;传入边的索引
boolean Adjancent1(MGraph *G,int vi,int wi){
if(G->Edge[vi][wi] == 1) return true;
else return false;
}
//插入一个新的顶点
boolean InsertV(MGraph *G,char v){
if(G->vexnum >= MaxSize || IsVEmpty(G,v)){
printf("存储顶点数的空间满了或者改结点存在!\n");
return false;
}
G->Vex[G->vexnum++] = v;
return true;
}
//插入边(v,w)
boolean AddEdge(MGraph *G,char v,char w){
if(!IsVEmpty(G,v) || !IsVEmpty(G,w)){
printf("输入的边其中有一个顶点或者两个顶点不存在\n");
return false;
}
//获取结点的索引
int vi = GetV_Index(G,v);
int wi = GetV_Index(G,w);
if(Adjancent1(G,vi,wi)){
printf("该边已经存在\n");
return false;
}
//修改邻接矩阵
G->Edge[vi][wi] = 1;
G->Edge[wi][vi] = 1;
//修改边数
G->arcnum++;
return true;
}
//删除边(v,w)
boolean RemoveEdge(MGraph *G,char v,char w){
if(!IsVEmpty(G,v) || !IsVEmpty(G,w)){
//判断这两个点是否存在
printf("这两个点不存在\n");
return false;
}
int vi = GetV_Index(G,v);
int wi = GetV_Index(G,w);
if(Adjancent1(G,vi,wi) == true){//存在该边就删除
G->Edge[vi][wi] = 0;
G->Edge[wi][vi] = 0;
G->arcnum--;//边减1
return true;
}else{
printf("删除的边不存在\n");
return false;
}
}
//获取某个结点v的所有邻接边
boolean NeighBors(MGraph *G,char v,char ***res,int *length){
if(!IsVEmpty(G,v)){
printf("输入的顶点不存在\n");
return false;
}
int vi = GetV_Index(G,v);
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[vi][i] == 1) {
(*length)++;
}
}
*res = (char **)malloc(sizeof(char)*(*length));
int index = 0;
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[vi][i] == 1) {
(*res)[index] = (char *)malloc(sizeof(char)*2);
(*res)[index][0] = v;
(*res)[index][1] = G->Vex[i];
index++;
}
}
return true;
}
//寻找某个结点V的所有邻接点
boolean Neighbors(MGraph *G,char V,int Vi,char **resNode,int **resIndex,int *length){
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[Vi][i] == 1){
(*length)++;
}
}
*resNode = (char *)malloc(sizeof(char)*(*length));
*resIndex = (int *)malloc(sizeof(int)*(*length));
int index = 0;
for(int i = 0;i < G->vexnum;i++){
if(G->Edge[Vi][i] == 1){
(*resNode)[index] = G->Vex[i];
(*resIndex)[index] = i;
index++;
}
}
return true;
}
//访问结点
void visitV(char *res,int resLength){
for(int i = 0;i < resLength;i++){
printf("%c ,",res[i]);
}
}
//深度优先遍历
void DFS(MGraph *G,char V,int Vi,char **res,int *resLength,boolean **visited){
(*visited)[Vi] = true;
(*res)[*resLength] = V;
(*resLength)++;
char *resChar;
int *resIndex;
int length = 0;
Neighbors(G,V,Vi,&resChar,&resIndex,&length);
for(int i = 0;i < length;i++){
if((*visited)[resIndex[i]] == false){
DFS(G,resChar[i],resIndex[i],res,resLength,visited);
}
}
}
//对图G进行广度优先遍历
void DFSMGraph(MGraph *G,char V){
int Vi = GetV_Index(G,V);
char *res = (char *)malloc(sizeof(char)*G->vexnum);
int resLength = 0;
boolean *visited = (boolean *)malloc(sizeof(boolean)*G->vexnum);
for(int i = 0;i < G->vexnum;i++){
visited[i] = false;
}
DFS(G,V,Vi,&res,&resLength,&visited);
for(int i = 0;i < G->vexnum;i++){
if(visited[i] == false){
DFS(G,G->Vex[i],i,&res,&resLength,&visited);
}
}
visitV(res,resLength);
}
int main(){
MGraph *G;
MG_Init(&G);
printf("顶点数:%d;边数:%d\n",G->vexnum,G->arcnum);
InsertV(G,'A');
InsertV(G,'B');
InsertV(G,'C');
InsertV(G,'D');
InsertV(G,'E');
InsertV(G,'F');
InsertV(G,'G');
InsertV(G,'H');
InsertV(G,'I');
InsertV(G,'J');
InsertV(G,'K');
printf("顶点数:%d;边数:%d\n",G->vexnum,G->arcnum);
AddEdge(G,'A','B');
AddEdge(G,'A','C');
AddEdge(G,'C','D');
AddEdge(G,'D','E');
AddEdge(G,'D','F');
AddEdge(G,'E','F');
AddEdge(G,'E','G');
AddEdge(G,'F','G');
AddEdge(G,'F','H');
AddEdge(G,'G','H');
AddEdge(G,'I','J');
AddEdge(G,'J','K');
AddEdge(G,'I','K');
printf("顶点数:%d;边数:%d\n",G->vexnum,G->arcnum);
DFSMGraph(G,'C');
return 0;
}
//结果:
顶点数:0;边数:0
顶点数:11;边数:0
顶点数:11;边数:13
C ,A ,B ,D ,E ,F ,G ,H ,I ,J ,K ,