后附代码
基础知识
有向图中
孤立点:V中不与E中任一条边关联的点称为D的孤立点.
简单图:不含平行边的图称为简单图.
完备图:图中任两个顶点U与u之间,恰有两条有向边(u,v),及(v,u),则称该有向图D为完备图.
基本图:把有向图D的每条边除去定向就得到一个相应的无向图G,称G为D的基本图.称D为G的定向图。
强连通图:给定有向图G=(VE),并且给定该图G中的任意两个结点u和v,如果结点u与结点v相互可达,即至少存在一条路径可以由结点u开始,到结点v终止,同时存在至少有一条路径可以由结点v开始,到结点u终止,那么就称该有向图G是强连通图。
弱连通图:若至少有一对结点不满足单向连通,但去掉边的方向后从无向图的观点看是连通图,则D称为弱连通图。
单向连通图:若每对结点至少有一个方向是连通的,则D称为单向连通图。
强连通分支:有向图G的极大强连通子图称为该有向图的强连通分支。
有向通路:无环有向图D中总存在这样一个独立集5,使得y—Js中任何一点",存在H∈S,从M到"有长度不超过2的有向通路。
有向图
有向图是一个二元组
通俗点就是有方向的图
无向图
边没有方向的图称为无向图。
直观来说,若一个图中每条边都是无方向的,则称为无向图。
(1)无向边的表示
无向图中的边均是顶点的无序对,无序对通常用圆括号表示。
【例】无序对(vi,vj)和(vj,vi)表示同一条边。
(2)无向图的表示
【例】下面(b)图中的G2和©图中的G3均是无向图,它们的顶点集和边集分别为:
V(G2)={v1,v2,v3,v4}
E(G2)={(vl,v2),(v1,v3),(v1,v4),(v2,v3),(v2,v4),(v3,v4)}
V(G3)={v1,v2,v3,v4,v5,v6,v7}
E(G3)={(v1,v2),(vl,v3),(v2,v4),(v2,v5),(v3,v6),(v3,v7)}
(3)若G是无向图,则0≤e≤n(n-1)/2
恰有n(n-1)/2条边的无向图称无向完全图(Undirected Complete Graph)
DFS(深度优先搜索)
深度优先遍历图的方法是,从图中某顶点v出发:
(1)访问顶点v;
(2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
(3)若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
BFS(广度优先搜索)
假设从图中某顶点出发,先访问了V之后依次访问V的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问他们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。
DFS和BFS的区别
源自 https://blog.csdn.net/sunny04/article/details/41911655
广度优先搜索(BFS),可以被形象的描述为“浅尝辄止”,具体一点就是每个顶点只访问它的邻接节点(如果它的邻接节点没有被访问)并且记录这个邻接节点,当访问完它的邻接节点之后就结束这个顶点的访问。
广度优先用到了“先进先出”队列,通过这个队列来存储第一次发现的节点,以便下一次的处理;而对于再次发现的节点,我们不予理会——不放入队列,因为再次发现的节点:
1、无非是已经处理完的了;
2、或者是存储在队列中尚未处理的。
深度优先搜索(DFS),可以被形象的描述为“打破沙锅问到底”,具体一点就是访问一个顶点之后,我继而访问它的下一个邻接的顶点,如此往复,直到当前顶点一被访问或者它不存在邻接的顶点。
1、WHITE 未访问顶点
2、GRAY 一条深度搜索路径上的顶点,即被发现时
3、BLACK 此顶点的邻接顶点被全部访问完之后——结束访问次顶点
DFS和BFS的优缺点
BFS:占内存多,能找到最优解,必须遍历所有分枝. 广优的一个应用就是迪科斯彻单元最短路径算法.
DFS:占内存少,能找到最优解(一定条件下),但能很快找到接近解(优点),可能不必遍历所有分枝(也就是速度快), 深优的一个应用就是连连看游戏.
在更多的情况下,深优是比较好的方案。
代码:
#include
#include
#include
#define MAX 100
//链表
typedef struct node{
int adjvexData; /*邻接点域*/
struct node *next; /*指向下一邻接点的指针域*/
}AD;
//首链表
typedef struct tnode{
char firstData; /*顶点域*/
AD *firstedge; /*指向第一条边结点*/
}FD;
//首数组
typedef struct{
FD arr[MAX]; /*邻接表头结点数组*/
int n,l; /*顶点数、边数*/
}Arr;
//构建图
void create (Arr &M,int flag){
int m,j,i,n,num1,num2;
AD *p,*p1;
printf("输入图的顶点数\n");
scanf("%d",&M.n);
printf("输入图的边数\n");
scanf("%d",&M.l);
printf("请输入图的各项信息\n");
for(i=0;iadjvexData=num2;
p->next=M.arr[num1].firstedge;
M.arr[num1].firstedge=p;
if(flag==0){ //无向图
p=(AD *)malloc(sizeof(AD));
p->adjvexData=num1;
p->next=M.arr[num2].firstedge;
M.arr[num2].firstedge=p;
}
}
}
int visit[MAX]; //用于判断是否遍历到
//深度优先递归算法
void DFS(Arr M,int i){
AD *p;
visit[i]=1;
printf("%c-->",M.arr[i].firstData);
p=M.arr[i].firstedge;
while(p){
if(!visit[p->adjvexData])
DFS(M,p->adjvexData);
p=p->next;
}
}
//深度遍历操作
void DFSTraverse(Arr M){
int i;
for(i=0;in;i++){
printf("%2d [%c]",i,M->arr[i].firstData);
p=M->arr[i].firstedge;
while(p){
printf("-->[%d]",p->adjvexData);
p=p->next;
}
printf("\n");
}
}
//广度优先搜索
void BFS(Arr *M){
int i,v;
int qu[MAX],front=0,rear=0; //循环队列
AD *p;
for(i=0;in;i++){
visit[i]=0;
}
printf("%C-->",M->arr[0].firstData);
visit[0]=1;
rear=(rear+1)%MAX; //队尾指针后移
while(front!=rear){
front=(front+1)%MAX;
v=qu[front]; //将队头元素出队
p=M->arr[v].firstedge;
while(p!=NULL){
if(visit[p->adjvexData]==0){
visit[p->adjvexData]=1;
printf("%c-->",M->arr[p->adjvexData].firstData);
rear=(rear+1)%MAX;
qu[rear]=p->adjvexData;
}
p=p->next;
}
}
}
int main(){
int flage;
Arr M;
printf("输入建立图的类型(1有向图 0无向图)\n");
scanf("%d",&flage);
create(M,flage);
printf("邻接表\n");
DisAGraph(&M);
printf("深度优先搜索\n");
DFSTraverse(M);
printf("\n广度优先搜索\n");
BFS(&M);
return 0;
}