图的四种存储结构
- 领接矩阵
- 领接表
- 十字链表(有向图)
- 领接多重表(无向图)
广度搜索优先算法描述
广度搜索优先算法类似于树的层次遍历算法。其基本思想为,首先访问顶点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);
}
}
图的遍历与图的连通性
图的遍历算法可以用来判断图的连通性。对于无向图来说,如果无向图是连通的,则从任一顶点出发,都可以一次访问所有顶点。若无向图是非连通的,需要遍历的次数等于连通分量数。有向图分为强连通分量和非强连通分量,如果有向图都是强连通分量,那么需要遍历的次数等于强连通分量数。