题目如下:
给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
输出格式:
按照"{ v1 v2 ... vk }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。
输入样例:
8 6
0 7
0 1
2 0
4 1
2 4
3 5
输出样例:
{ 0 1 4 2 7 } { 3 5 } { 6 } { 0 1 2 7 4 } { 3 5 } { 6 }
/*------------------------------------------------------------------------------------------------------*/
刚开始时候我采用邻接链表的形式:到最后发现如果进行遍历的时候没有采用邻接矩阵这样方便,
后来才发现:邻接链表:对于稀疏矩阵是十分有用; 对于稠密矩阵最好采用邻接矩阵法
1 #include<iostream> 2 #include<cstdio> 3 #include<malloc.h> 4 #include<queue> 5 using namespace std; 6 7 #define Null -1 8 #define MAX 50 9 /*构造邻接表*/ 10 int Visited[MAX]; 11 typedef struct _EdgNode{ 12 int Adjv; 13 struct _EdgNode *Next; 14 15 }EdgNode; 16 17 typedef struct _VNode{ 18 //int Weight; 19 int VN; 20 EdgNode *first_Edg;//通过其第一条边进行下一个顶点之间连接 21 }VNode; 22 23 typedef struct _LGraph{ 24 int vexnum; 25 int edgnum; 26 VNode Vex[MAX]; 27 }LGraph; 28 29 LGraph *PG; 30 31 EdgNode * link_last(EdgNode *list,EdgNode *node) 32 { 33 /*由于第一条边被人所占了,说明还有其他点与此点相连接的,同时在插入可以进行排序*/ 34 //在这里排序的过程中分了两种情况第一种首地址就开始比Node小,直接用Node->next=list 35 //第二种情况是首地址最小,在中间插入,必须要不断进行判断p->next进行判断 36 EdgNode *p=list,*t=list; 37 38 while(p!=NULL) 39 { 40 if(node->Adjv<p->Adjv) 41 { 42 node->Next=p; 43 list=node; 44 return list; 45 break; 46 } 47 else if( p->Next!=NULL && node->Adjv<p->Next->Adjv ) 48 { 49 node->Next=p->Next; 50 p->Next=node; 51 return list; 52 break; 53 } 54 else 55 { p->Next=node; 56 node->Next=NULL; 57 p=p->Next; 58 } 59 return list; 60 } 61 62 } 63 64 LGraph *create_LGraph() 65 { 66 int Vex,Edg; 67 cin>>Vex>>Edg; //输入顶点数、边数 68 LGraph *pG; 69 EdgNode *ednode; 70 71 pG=(LGraph*)malloc(sizeof(struct _LGraph)); 72 memset(pG,-1,sizeof(LGraph)); 73 pG->vexnum=Vex;pG->edgnum=Edg; 74 75 //将点进行初始化 76 for(int i=0;i<Vex;i++) 77 { 78 pG->Vex[i].VN=i; 79 pG->Vex[i].first_Edg=NULL; 80 81 } 82 83 //开始输入数据 84 int c1,c2,i,j; 85 for (int j=0;j<Edg;j++) 86 { 87 cin>>c1>>c2; 88 ednode=(EdgNode*)malloc(sizeof(EdgNode)); 89 ednode->Adjv=c2;ednode->Next=NULL; 90 for( i=0;i<Vex;i++) 91 { 92 if(c1==pG->Vex[i].VN) 93 { 94 if(pG->Vex[i].first_Edg==NULL) 95 { 96 pG->Vex[i].first_Edg=ednode; 97 pG->Vex[i].first_Edg->Next=NULL; 98 } 99 else 100 { 101 pG->Vex[i].first_Edg= link_last(pG->Vex[i].first_Edg,ednode); 102 } 103 } 104 } 105 /*-----这里只建立起来单个方向的存贮-------*/ 106 ednode=(EdgNode*)malloc(sizeof(EdgNode)); 107 ednode->Adjv=c1;ednode->Next=NULL; 108 for( i=0;i<Vex;i++) 109 { 110 if(c2==pG->Vex[i].VN) 111 { 112 if(pG->Vex[i].first_Edg==NULL) 113 { 114 pG->Vex[i].first_Edg=ednode; 115 pG->Vex[i].first_Edg->Next=NULL; 116 } 117 else 118 { 119 pG->Vex[i].first_Edg= link_last(pG->Vex[i].first_Edg,ednode); 120 } 121 } 122 } 123 } 124 return pG; 125 } 126 void DFS(int V,EdgNode *p) 127 { 128 Visited[V]=true; 129 printf("%d",V); 130 if(p!=NULL) 131 { 132 while(p!=NULL) 133 { 134 if(!Visited[p->Adjv]) 135 { 136 DFS(PG->Vex[p->Adjv].VN,PG->Vex[p->Adjv].first_Edg); 137 } 138 p=p->Next; 139 } 140 } 141 else 142 { 143 144 return; 145 } 146 } 147 148 void ListComponentsWithDFS( LGraph *P){ 149 for(int V=0;V<P->vexnum;V++) 150 { 151 if(!Visited[V]) 152 { 153 printf("{"); 154 DFS(V,PG->Vex[V].first_Edg); 155 printf("}"); 156 } 157 } 158 159 } 160 queue<int>q,R; 161 //求BFS进行的是层次遍历需要用到队列 162 void BFS_1(int V,EdgNode *p) 163 { 164 while(p!=NULL) 165 { 166 if(Visited[p->Adjv]) 167 { 168 p=p->Next; 169 } 170 else 171 { 172 q.push(p->Adjv); 173 Visited[p->Adjv]=true; 174 p=p->Next; 175 } 176 } 177 178 } 179 180 void BFS(int V,EdgNode *p) 181 { 182 183 if(!Visited[V]) 184 { q.push(V); 185 Visited[V]=true; 186 } 187 while(!q.empty()) 188 { 189 while(p!=NULL) 190 { 191 if(!Visited[p->Adjv]) 192 { q.push(p->Adjv); 193 Visited[p->Adjv]=true; 194 } 195 p=p->Next; 196 197 198 } 199 cout<<q.front()<<" "; 200 q.pop(); 201 if(!q.empty()) 202 {//对其进行次级路 203 BFS_1(PG->Vex[q.front()].VN,PG->Vex[q.front()].first_Edg); 204 } 205 } 206 } 207 208 void ListComponentsWithBFS( LGraph *P) 209 { 210 for(int V=0;V<P->vexnum;V++) 211 { 212 if(!Visited[V]) 213 { 214 printf("{"); 215 BFS(V,P->Vex[V].first_Edg);//BFS采用的是层次遍历 216 printf("}"); 217 } 218 } 219 220 221 } 222 223 224 int main() 225 { 226 227 PG=create_LGraph(); 228 //开始进行DFS遍历 229 ListComponentsWithDFS(PG); 230 memset(Visited,0,sizeof(Visited)); 231 ListComponentsWithBFS(PG); 232 return 0; 233 }
/*------------------到了这里采用邻接链表并且是无向图,发现在做DFS递归方式很复杂-------------------------*/
在此我想了一个办法由于从小到大的遍历,同时要用上邻接链表的形式:只要在插入时候开始进行排序对每一行的相邻顶点从小到大排序,同时可以比较一下用邻接链表和邻接矩阵之后代码的复杂度,(不够值得欣慰的是小白对代码理解度又增高了一点)
从这里得到一个启示:编程的代码不是越复杂就越好,其实是对问题以最佳的,最简单的方式书写,解决问题才是最重要的,最简洁,最便捷手段才是编程高手所需要的素质。
#include <cstdio> #include<queue> #include<iostream> #include<cstdlib> using namespace std; #define N 15 void ListComponentsWithDFS(); void ListComponentsWithBFS(); void DFS(int V); void BFS(int V); void InitVisit(void); int n; bool Visited[N];//这个是个监控举证 int G[N][N] = {0}; int main() { int E; scanf("%d%d", &n, &E); for (int i = 0; i < E; i++) { int a, b; scanf("%d%d", &a, &b); G[b][a] = G[a][b] = 1;//在这里建立邻接矩阵的形式 } ListComponentsWithDFS(); cout<<" "<<endl; InitVisit(); ListComponentsWithBFS(); return 0; } void InitVisit() { for(int i=0;i<N;i++) { Visited[i]=false; } } void ListComponentsWithDFS(){ for(int V=0;V<n;V++) { if(!Visited[V]) { printf("{"); DFS(V); printf("}"); } } } void DFS(int V) { Visited[V]=true; printf("%d",V); cout<<" "; for(int i=0;i<n;i++) { if(G[V][i] &&!Visited[i]) DFS(i); } } void ListComponentsWithBFS() { for(int V=0;V<n;V++) { if(!Visited[V]) { printf("{"); BFS(V);//BFS采用的是层次遍历 printf("}"); } } } void BFS(int V) { queue<int>q; //如果采用层次遍历必须要将其从小到大遍历,借用队列形式 q.push(V);int c; Visited[V]=true; while(!q.empty()) { cout<<q.front()<<" "; for(int j=0;j<n;j++) { if(G[q.front()][j] && !Visited[j]) { q.push(j); Visited[j]=true; } } q.pop(); } }