图-存储结构 广度搜索优先和深度搜索优先算法

324 阅读3分钟

图的四种存储结构

  • 领接矩阵
  • 领接表
  • 十字链表(有向图)
  • 领接多重表(无向图)

广度搜索优先算法描述

广度搜索优先算法类似于树的层次遍历算法。其基本思想为,首先访问顶点v,接着从v出发依次访问未被访问的于v领接的顶点w1,w2,...,wi,然后依次访问w1,w2,...,wi的所有未访问的领接顶点;再从这些访问过的顶点出发,依次访问所有未访问的领接结点,直到所有的结点都访问完为止。

广度优先搜索算法求解无权图的单源最短路径

注意是无权图,带权图要用dijkstra算法

#define INFINITE INT_MIN
int d[MaxVertexNum];

//求解顶点u到其他各顶点的路径长度
BSF(Graph G, int u){
	int i;
    for(i = 0; i < G.vernum; i ++){ //初始化路径长度
   		d[i] = INFININE;
    }
    visited[u] = TRUE;
    d[u] = 0;
    InitQueue(Q);
    EnQueue(Q, u);
    while(!Empty(Q)){
    	for(w = FirstNeighbor(G, u); w >= 0; w = NextNeighbor(G, u, w)){
        	if(!visited[w]){
            	visited[w] = TRUE;
                d[w] = d[u] + 1;
                EnQueue(Q,w);
            }
        }
    }
}

深度优先搜索算法描述

深度优先搜索算法类似于树的先序遍历。其基本思想为:先访问图中某一起始顶点,然后由v出发,访问与v领接的任一未访问顶点w1,再访问与w1领接的任一未访问的顶点w2,重复上述过程。当不能在继续向下访问时,依次退回到最近被访问的顶点,若它还有领接顶点未被访问过,则从该点继续上述搜索过程,直至所有顶点均被访问过为止。

领接矩阵

#define MaxVertexNum 100
typedef char VertexType; //顶点的数据类型
typedef int ArcType; //带权图中边上权值的数据类型
typedef struct{
	VertexType vexs[MaxVertexNum];
    ArcType arcs[MaxVertexNum][MaxVertexNum];
    int vexnum, arcnum; //图的当前顶点数和弧数
}MGraph;

图的广度搜索优先遍历

int FirstNeighbor(MGraph G, int v){ //获取顶点v的第个领接顶点。没有则返回-1
	for(int i = 0; i < G.vernum; i ++){
    	if(G.arcs[v][i] != 0) return i;
    }
    return -1;
}

int NextNeighbor(MGraph G, int v, int w){//获取顶点v的相对w的下一个领接顶点,没有返回-1。
	for(int i = 0; i < G.vernum; i ++){
    	if(G.arcs[v][i] == w){
        	for(int j = i + 1; j < G.vernum; j ++){
            	if(G.arcs[v][j] != 0) return j;
            }
            return -1;
        }
    }
    return -1;
}

bool visited[MaxVertexNum]; //访问标记数组
void BFSTraverse(MGraph G){
	for(int i = 0; i < G.vernum; i ++)
    	visited[i] = FALSE; //访问标记数组初始化
    InitQueue(Q);
    for(int i = 0; i < G.vernum; i++){
    	if(!visited[i]){
        	BFS(G, i, Q);
        }
    }
}

void BFS(MGraph G, int v, Queue &Q){
	int w;
	visit(v); //访问顶点v
	visited[v] = true;
    Enqueue(Q, v); //顶点v入队
    while(!Empty(Q)){
    	DeQueue(Q, v); 顶点v出队
        for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w){
            if(!visited[w]){
                visit(w);
                visited[w] = TRUE;
                EnQueue(Q, w);
            }
        } 
    }
}

图的深度优先搜索遍历

bool visited[MaxVertexNum]; //数组访问标记
void DFSTraverse(MGraph G){
	for(int i = 0; i < G.vernum; i ++){ //标记数组初始化
    	visited[i] = FALSE;
    }
    
    for(int i = 0; i < G.vernum; i ++){ //遍历访问顶点
    	if(!visited[i]){
        	DFS(G, i);
        }
    }
}
void DFS(MGraph G, int v){
	int w;
	visit(v);
    visited[v] = TRUE;
    for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
    	if(!visited[w]){
            DFS(G, w);
        }
    }
}

领接表

#define MaxVertexNum 100
typedef struct ArcNode{ //边表结点
	int adjvex; //该弧所指向的顶点的位置
    struct ArcNode *next; //指向下一条弧的指针
}ArcNode;
typedef struct VNode{
	VertexType data; //顶点信息
    ArcNode *first; //指向第一条依附该顶点的弧的指针
}VNode, AdjList[MaxVerNum];
typedef struct{
	AdjList vertices; //领接表
    int vernum, arcnum; //图的边数和弧数
}ALGraph;

图的广度搜索优先遍历

bool visited[MaxVertexNum]; //访问标记数组
void BFSTraverse(ALGraph G){
    initQueue(Q);
    for(int i = 0; i < G.vernum; i ++){ //访问标记数组初始化
    	visited[i] = FALSE;
    }
    
    for(int i = 0; i < G.vernum; i ++){
    	if(!visited[i]){	
        	BFS(G, i, Q);
        }
    }
}

void BFS(ALGraph G, int v, Queue &Q){
	int w;
	visit(v);
    visited[v] = TRUE;
    EnQueue(Q, v);
    while(!Empty(Q)){	
    	Dequeu(Q, v);
    	for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
        	if(!visited[w]){
            	visit(w);
                visited[w] = TRUE;
                EnQueue(Q, w);
            }
        }
    }
}

图的深度优先搜索算法

算法与领接矩阵的算法相同。可见,尽管实现的数据结构不通,但是算法实现确实一致的,这体现了算法是抽象的,是一种思想。

bool visited[MaxVertexNum];
void DFSTraverse(ALGraph G){
	for(int i = 0; i < G.vernum; i ++){
    	visited[i] = FALSE;
    }
    
    for(int i = 0; i < G.vernum; i ++){
    	if(!visited[i]) DFS(G, i);
	}
}

void DFS(ALGraph G, int v){
	int w;
	visit(v);
	visited[v] = TRUE;
    for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
    	if(!visited[w]) DFS(G, w);
    }
}

图的遍历与图的连通性

图的遍历算法可以用来判断图的连通性。对于无向图来说,如果无向图是连通的,则从任一顶点出发,都可以一次访问所有顶点。若无向图是非连通的,需要遍历的次数等于连通分量数。有向图分为强连通分量和非强连通分量,如果有向图都是强连通分量,那么需要遍历的次数等于强连通分量数。