图:

目录:

1.概念

2.邻接矩阵(结构,深度/广度优先遍历)

3.邻接表(结构,深度/广度优先遍历)

图的基本概念:

数据元素:顶点

1.有穷非空(必须有顶点)

2.顶点之间为边(可空)

无向图:边没有方向,用(vi,vj)表示,(vj,vi)也可。

有向图:边有方向,称为弧,用<vi,vj>表示。vi尾,vj头

简单图:不存在顶点到其自身的边,且同一条边不重复出现。

无向完全图:无向图中,所有的顶点都有边连接。 边的条数:n*(n-1)/2

有向完全图:在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧。

有很少条边或者弧的图称 稀疏图,反之称为稠密图。

边的相关数称为权。

图的存储

有向图:

  入度:就是指向该顶点的边的个数

  出度:就是该顶点指向其他顶点的边的个数

存放图的方式:

1.邻接矩阵

2.邻接表

3.十字链表

4.邻接多重表

5.边集数组

遍历:

1.深度优先遍历(DFS)

假设给定图G的初态是所有顶点均未曾访问过。
在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:
  首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。
  若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。
  若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
 
图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。

2.广度优先遍历(BFS)

  从图中某个顶点V0出发,并访问此顶点;
  从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点;
  重复步骤2,直到全部顶点都被访问为止。
 
图的广度优先遍历类似于树的层序遍历。

-------------------------------------------------------------------------------------

================================================

以此无向图作例子:

##################################################################

(1).邻接矩阵(9个顶点)

##################################################################

我们需要一个顶点数组,一个边数组:

顶点数组 {A,B,C,D,E,F,G,H,I}

边数组:

(其中 $代表无临边,在数组总存放为65535)

a.结构:

#define MAXVEX 100
#define IFY 65535 typedef char VertexType;
typedef int EdgeType; //静态图-邻接矩阵
typedef struct {
VertexType vexs[MAXVEX];
EdgeType Mat[MAXVEX][MAXVEX];
int numVexs,numEdges;
}MGraph;

存储形式:
一个数组存放顶点;一个二维数组存放邻接矩阵。

b.初始化图:

bool checkMat(EdgeType *p,VertexType numvex)
{
int i,j;
for (i=;i<numvex;i++)
{
for(j=i+;j<numvex;j++)
{
//printf("[%d][%d] = %d\t",i,j,*(p + MAXVEX*i + j));
//printf("[%d][%d] = %d\n",j,i,*(p + MAXVEX*j + i));
if (*(p + MAXVEX*i + j) != *(p + MAXVEX*j +i) )
{
printf("ERROR:Mat[%d][%d] or Mat[%d][%d] not equal!\n",i,j,j,i);
return false;
}
}
}
return true;
} void init_Grp(MGraph *g,VertexType *v,EdgeType *p)
{
int i,j;
// init vex num
(*g).numVexs = getVexNum(v); //init vexter
for (i=;i<(*g).numVexs;i++)
{
(*g).vexs[i]=*v;
v++;
} //init Mat
for (i=;i<(*g).numVexs;i++)
{
for (j=;j<(*g).numVexs;j++)
{
(*g).Mat[i][j] = *(p + MAXVEX*i + j);
}
}
if(checkMat(&((*g).Mat[][]),(*g).numVexs) == false)
{
printf("init error!\n");
exit();
}
}

c1:深度优先遍历:

//DFS
void DFS(MGraph G,int num)
{
int j;
g_visited[num]=true;
printf(" %c ",G.vexs[num]); for (j = ;j<G.numVexs;j++)
{ if (!g_visited[j] && G.Mat[num][j] == )
{
//printf("g_vis[%d] = %d",j,g_visited[j]);
//printf("Mat[%d][%d] = %d\n",num,j,G.Mat[num][j]);
DFS(G,j);
}
}
} void grp_DFS(MGraph G)
{
int i;
for (i=;i<G.numVexs;i++) // (1)
{
g_visited[i] = false;
}
for (i=;i<G.numVexs;i++) // (2)
{
if (!g_visited[i])
{
  DFS(G,i);
}
}
}

解释:
在grp_DFS()函数中,(1)对每个顶点初始化,记录顶点是否被访问过。

           (2)对每个没有被访问过的顶点访问。

在DFS()函数中:

for (j = ;j<G.numVexs;j++)
        if (!g_visited[j] && G.Mat[num][j] == )
判断该点是否被访问过而且有边,对每个顶点进行递归调用。

下图:

红色:grp_DFS()中,第一次调用时,访问A。从A开始递归调用。

从A开始,首先设置 g_visited[0] = true;判断edge[0][0](A自己)--> [0][1](B顶点),递归调用DFS()。(注意这里还没完成,在最后递归调用完成后还会继续判断[0][2]...[0][8])。

进入B,首先设置g_visited[1] = true;判断edge[1][0](A访问过了) --> [1][1](B自己)-->[1][2](C顶点),递归调用

。。。

绿色:进入G,首先设置g_visited[1] = true;判断edge[6][0] ...[6][8] (DFS函数中for全部循环完成),退出 --->退回到F,继续完成F的DFS的for循环 --->

  退回到E,继续完成DFS的for,进入到H。如此。。。

  ---> E  ---> D ---> C ---> B ---> I

最后退回到A,完成DFS的for循环。

我们可以发现,连通图只需要调用了grp_DFS() 即可完成全部循环。

深度优先遍历完整代码:

#include "stdafx.h"
#include <stdlib.h> #define MAXVEX 100
#define IFY 65535 typedef char VertexType;
typedef int EdgeType; //静态图-邻接矩阵
typedef struct {
VertexType vexs[MAXVEX];
EdgeType Mat[MAXVEX][MAXVEX];
int numVexs,numEdges;
}MGraph; VertexType g_init_vexs[MAXVEX] = {
'A','B','C','D','E','F','G','H','I'}; EdgeType g_init_edges1[MAXVEX][MAXVEX] = {
{,,IFY,IFY,IFY,,IFY,IFY,}, //'A'
{,,,IFY,IFY,IFY,IFY,IFY,}, //'B'
{IFY,,,,IFY,IFY,IFY,IFY,IFY},//'C'
{IFY,IFY,,,,IFY,IFY,IFY,IFY},//'D'
{IFY,IFY,IFY,,,,,,IFY}, //'E'
{,IFY,IFY,IFY,,,,IFY,IFY}, //'F'
{IFY,IFY,IFY,IFY,,,,IFY,IFY}, //'G'
{IFY,IFY,IFY,IFY,,IFY,IFY,,IFY}, //'H'
{,,IFY,IFY,IFY,IFY,IFY,IFY,}, //'I'
}; bool g_visited[MAXVEX]; //打印数组
void prt_maxtix(EdgeType *p,int vexs)
{
int i,j;
for (i=;i<vexs;i++)
{
printf("\t");
for (j=;j<vexs;j++)
{
if( (*(p + MAXVEX*i + j)) == IFY)
{
printf(" $ ");
}
else
{
printf(" %d ", *(p + MAXVEX*i + j));
}
}
printf("\n");
}
} //check the number of vextex
int getVexNum(VertexType *vexs)
{
VertexType *pos = vexs;
int cnt=;
while(*pos <= 'Z' && *pos >= 'A')
{
cnt++;
pos++;
}
return cnt;
} //DFS
void DFS(MGraph G,int num)
{
int j;
g_visited[num]=true;
printf(" %c ",G.vexs[num]); for (j = ;j<G.numVexs;j++)
{ if (!g_visited[j] && G.Mat[num][j] == )
{
//printf("g_vis[%d] = %d",j,g_visited[j]);
//printf("Mat[%d][%d] = %d\n",num,j,G.Mat[num][j]);
DFS(G,j);
}
}
} void grp_DFS(MGraph G)
{
int i;
for (i=;i<G.numVexs;i++)
{
g_visited[i] = false;
}
for (i=;i<G.numVexs;i++)
{
if (!g_visited[i])
{
//printf("xxx[%d]\n",i);
DFS(G,i);
}
}
} bool checkMat(EdgeType *p,VertexType numvex)
{
int i,j;
for (i=;i<numvex;i++)
{
for(j=i+;j<numvex;j++)
{
//printf("[%d][%d] = %d\t",i,j,*(p + MAXVEX*i + j));
//printf("[%d][%d] = %d\n",j,i,*(p + MAXVEX*j + i));
if (*(p + MAXVEX*i + j) != *(p + MAXVEX*j +i) )
{
printf("ERROR:Mat[%d][%d] or Mat[%d][%d] not equal!\n",i,j,j,i);
return false;
}
}
}
return true;
} void init_Grp(MGraph *g,VertexType *v,EdgeType *p)
{
int i,j;
// init vex num
(*g).numVexs = getVexNum(v); //init vexter
for (i=;i<(*g).numVexs;i++)
{
(*g).vexs[i]=*v;
v++;
} //init Mat
for (i=;i<(*g).numVexs;i++)
{
for (j=;j<(*g).numVexs;j++)
{
(*g).Mat[i][j] = *(p + MAXVEX*i + j);
}
}
if(checkMat(&((*g).Mat[][]),(*g).numVexs) == false)
{
printf("init error!\n");
exit();
}
} int _tmain(int argc, _TCHAR* argv[])
{
MGraph grp; init_Grp(&grp,g_init_vexs,&g_init_edges1[][]); //print the number of Vexters
printf("vex num = %d\n",grp.numVexs); //print the maxtix
prt_maxtix(&grp.Mat[][],grp.numVexs); grp_DFS(grp); getchar();
return ;
}

结果:

--------------------------------------------------------------------------------------------------

c2:广度优先遍历

void BFS(MGraph G)
{
int i,j;
spQueue que;
init_Queue(&que); for (i=;i<G.numVexs;i++)
{
g_visited[i]=false;
}
for (i=;i<G.numVexs;i++)
{
if (!g_visited[i])
{
g_visited[i]=true;
unshiftQueue(&que,i);
printf(" %c ",G.vexs[i]); while(!isEmptyQueue(que))
{
QueueType crnt = shiftQueue(&que);
for (j=;j<G.numVexs;j++)
{
if (!g_visited[j] && G.Mat[crnt][j] == )
{
g_visited[j]=true;
unshiftQueue(&que,j);
printf(" %c ",G.vexs[j]);
}
}
i=crnt;
} }
}
}

解释:

从一个顶点开始,查看所有和他相连的顶点;从这些相连的顶点中逐次查找与它们相连且没有访问过的点。

这里要借助一个辅助的数据结构---队列。

如下,先将图转化为右边形式。

第一层为A,第二层为B I F,第三层为C G E,第四层为 D H。

  过程:

  a.A开始,A进队。

队列  | A |

  b.队列出队一个元素(此时为A),查找与它相连且没有被访问过的元素(B、I、F),使其进队。

队列    A | | -->  | B I F |  第一层完成

---

  c.重复b过程,直到队列中没有元素为止。 (如果是连通图,则此时全部访问,否则继续查其他顶点,直到所有顶点都遍历。)

    队列出列一个元素(此时为B),查找与它相连且没有被访问过的元素(C),使其进队。

队列    B | I F|--> | I F C|

    队列出列一个元素(此时为I),。。。                                      (无)

队列    I | F C | --> | F  C |

    队列出列一个元素(此时为F),。。。                                      (G、E),使其进队。

队列   F | C | ---> | C G E |  第二层完成

---

队列   C | G E | ---> | G E D|

队列   G | E D | ---> |E D|

队列   E | D |    ---> | D H|

队列   D | H |   ---> | H |

队列   H ||   完成。。。

完整程序如下:

// grp-mat-bfs-self.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h> #define MAXVEX 100
#define IFY 65535 typedef char VertexType;
typedef int EdgeType; typedef int QueueType; bool g_visited[MAXVEX]; VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I'}; EdgeType g_init_edges[MAXVEX][MAXVEX] = {
{,,IFY,IFY,IFY,,IFY,IFY,}, //'A'
{,,,IFY,IFY,IFY,IFY,IFY,}, //'B'
{IFY,,,,IFY,IFY,IFY,IFY,IFY},//'C'
{IFY,IFY,,,,IFY,IFY,IFY,IFY},//'D'
{IFY,IFY,IFY,,,,,,IFY}, //'E'
{,IFY,IFY,IFY,,,,IFY,IFY}, //'F'
{IFY,IFY,IFY,IFY,,,,IFY,IFY}, //'G'
{IFY,IFY,IFY,IFY,,IFY,IFY,,IFY}, //'H'
{,,IFY,IFY,IFY,IFY,IFY,IFY,}, //'I'
}; //==========================================================================
//静态图-邻接矩阵
typedef struct {
VertexType vexs[MAXVEX];
EdgeType Mat[MAXVEX][MAXVEX];
int numVexs,numEdges;
}MGraph; //==========================================================================
//队列 //队列节点
typedef struct Node {
QueueType data;
struct Node *next;
}QNode,*qQNode; //队列指示
typedef struct {
int length;
qQNode frnt,rear;
}spQueue; void init_Queue(spQueue *Q)
{
(*Q).frnt = NULL;
(*Q).rear = NULL;
(*Q).length = ;
}
bool isEmptyQueue(spQueue Q)
{
if (Q.length == )
{
return true;
}
return false;
}
//进队
void unshiftQueue(spQueue *Q,QueueType elem)
{
//队列空
if (isEmptyQueue(*Q))
{
qQNode n = (qQNode)malloc(sizeof(QNode));
n->data = elem;
n->next = NULL; (*Q).frnt = n;
(*Q).rear = n;
(*Q).length = ;
}
else
{
qQNode n = (qQNode)malloc(sizeof(QNode));
n->data = elem;
n->next = NULL; (*Q).rear->next = n; (*Q).rear = n;
(*Q).length++;
}
} //出队
QueueType shiftQueue(spQueue *Q)
{
if (isEmptyQueue(*Q))
{
printf("Warning:Queue is empty!!!\n");
return NULL;
}
if ((*Q).length == )
{
QueueType sh = (*Q).frnt->data;
(*Q).frnt = NULL;
(*Q).rear = NULL;
(*Q).length = ;
return sh;
}
QueueType sh = (*Q).frnt->data;
(*Q).frnt = (*Q).frnt->next;
(*Q).length--; return sh;
} //打印队列
void prt_que(spQueue que)
{
if (isEmptyQueue(que))
{
return ;
}
qQNode pos = que.frnt;
while(que.rear->next != pos && pos != NULL)
{
printf(" %d ",pos->data);
pos = pos->next;
}
printf("\n");
} //====================================================================
//打印矩阵
void prt_maxtix(EdgeType *p,int vexs)
{
int i,j;
for (i=;i<vexs;i++)
{
printf("\t");
for (j=;j<vexs;j++)
{
if( (*(p + MAXVEX*i + j)) == IFY)
{
printf(" $ ");
}
else
{
printf(" %d ", *(p + MAXVEX*i + j));
}
}
printf("\n");
}
} //check the number of vextex
int getVexNum(VertexType *vexs)
{
VertexType *pos = vexs;
int cnt=;
while(*pos <= 'Z' && *pos >= 'A')
{
cnt++;
pos++;
}
return cnt;
} bool checkMat(EdgeType *p,VertexType numvex)
{
int i,j;
for (i=;i<numvex;i++)
{
for(j=i+;j<numvex;j++)
{
//printf("[%d][%d] = %d\t",i,j,*(p + MAXVEX*i + j));
//printf("[%d][%d] = %d\n",j,i,*(p + MAXVEX*j + i));
if (*(p + MAXVEX*i + j) != *(p + MAXVEX*j +i) )
{
printf("ERROR:Mat[%d][%d] or Mat[%d][%d] not equal!\n",i,j,j,i);
return false;
}
}
}
return true;
} void init_Grp(MGraph *g,VertexType *v,EdgeType *p)
{
int i,j;
// init vex num
(*g).numVexs = getVexNum(v); //init vexter
for (i=;i<(*g).numVexs;i++)
{
(*g).vexs[i]=*v;
v++;
} //init Mat
for (i=;i<(*g).numVexs;i++)
{
for (j=;j<(*g).numVexs;j++)
{
(*g).Mat[i][j] = *(p + MAXVEX*i + j);
}
}
if(checkMat(&((*g).Mat[][]),(*g).numVexs) == false)
{
printf("init error!\n");
exit();
}
} void BFS(MGraph G)
{
int i,j;
spQueue que;
init_Queue(&que); for (i=;i<G.numVexs;i++)
{
g_visited[i]=false;
}
for (i=;i<G.numVexs;i++)
{
if (!g_visited[i])
{
g_visited[i]=true;
unshiftQueue(&que,i);
printf(" %c ",G.vexs[i]); while(!isEmptyQueue(que))
{
QueueType crnt = shiftQueue(&que);
for (j=;j<G.numVexs;j++)
{
if (!g_visited[j] && G.Mat[crnt][j] == )
{
g_visited[j]=true;
unshiftQueue(&que,j);
printf(" %c ",G.vexs[j]);
}
}
i=crnt;
} }
}
} int _tmain(int argc, _TCHAR* argv[])
{
MGraph grp;
init_Grp(&grp,g_init_vexs,&g_init_edges[][]); BFS(grp); getchar();
return ;
}

结果:

=================================================================

##################################################################

(2).邻接表

##################################################################

如上图:

邻接表如下:

顶点   边

A      -> B -> F -> I

B      -> A -> C -> I

C      -> B -> D

D      -> C -> E

E       -> D -> F -> G -> H

F       -> A -> E -> G

G       -> E -> F

H       -> E

I        -> A -> B

结构:

#define MAXVEX 100
#define IFY 65535 typedef char VertexType;
typedef int EdgeType;
typedef int ArrayIdx; //边节点
typedef struct EdgeNode{
ArrayIdx idx;
struct EdgeNode* next;
}edgeNode;
//顶点节点
typedef struct VexNode{
ArrayIdx idx;
edgeNode *fitstedge;
}vexNode; //图的集合:包含了一个顶点数组
typedef struct {
vexNode adjList[MAXVEX];
int numVextexs,numEdges;
}GraphAdjList;

我通过一个二维字符数组来初始化该图结构:

VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I'};
//====================================
char *g_input[] = {
"A->B->F->I",
"B->A->C->I",
"C->B->D",
"D->C->E",
"E->D->F->G->H",
"F->A->E->G",
"G->E->F",
"H->E",
"I->A->B"
};

初始化函数:

void init_GrapAdjList(GraphAdjList *g,char **str)
{
char **pos = str;
int cnt=;
while (*pos != NULL) //g_input的每行的首指针
{
int i=;
while(**pos != NULL) //g_input的每行字母
{
if(isVexter(**pos)) //判断是否为顶点(我规定‘A’-‘Z’之间为顶点标志)
{
if (i == ) //建立顶点的节点
{
(*g).adjList[cnt].idx = strFindIdx(**pos);
(*g).adjList[cnt].fitstedge = NULL;
i=;
}
else if(i == ) //建立第一个边的节点
{
edgeNode* n = (edgeNode*)malloc(sizeof(edgeNode));
n->idx = strFindIdx(**pos);
n->next = NULL; (*g).adjList[cnt].fitstedge = n;
i=;
}
else //边节点连接到前一个边节点上
{
edgeNode* n = (edgeNode*)malloc(sizeof(edgeNode));
n->idx = strFindIdx(**pos);
n->next = NULL; //first splist
edgeNode *r = (*g).adjList[cnt].fitstedge;
while (r->next != NULL)
{
r = r->next;
}
r->next = n;
}
}
(*pos)++;
}
pos++;
cnt++;
}
(*g).numVextexs = cnt;
}

这样之后,

内存中,以其中A为例子:

idx 为 索引值 0 ---> 'A'

0(A)---> 1(B) ---> 5(F) ---> 8(I)。

深度优先遍历(邻接矩阵类似)

遍历顺序为:

代码:

void DFS(GraphAdjList GL,int i)
{
edgeNode *p;
g_visited[i]=true;
printf(" %c ",g_init_vexs[GL.adjList[i].idx]); p = GL.adjList[i].fitstedge;
while(p)
{
if (!g_visited[p->idx])
{
DFS(GL,p->idx);
}
p=p->next;
}
} void DFS_Trvs(GraphAdjList GL)
{
int i;
for (i = ;i<GL.numVextexs;i++)
{
g_visited[i] = false;
}
for (i=;i<GL.numVextexs;i++)
{
if (!g_visited[i])
{
DFS(GL,i);
} }
}

结果:

完整代码:

// grp-tab-dfs.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h> #define MAXVEX 100
#define IFY 65535 typedef char VertexType;
typedef int EdgeType;
typedef int ArrayIdx; //边节点
typedef struct EdgeNode{
ArrayIdx idx;
struct EdgeNode* next;
}edgeNode;
//顶点节点
typedef struct VexNode{
ArrayIdx idx;
edgeNode *fitstedge;
}vexNode; //图的集合:包含了一个顶点数组
typedef struct {
vexNode adjList[MAXVEX];
int numVextexs,numEdges;
}GraphAdjList; bool g_visited[MAXVEX]; VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I'};
//====================================
char *g_input[] = {
"A->B->F->I",
"B->A->C->I",
"C->B->D",
"D->C->E",
"E->D->F->G->H",
"F->A->E->G",
"G->E->F",
"H->E",
"I->A->B"
}; ArrayIdx strFindIdx(char ch)
{
int i=;
VertexType *p = g_init_vexs;
while(p != NULL)
{
if(*p == ch)
{
return i;
}
p++;
i++;
}
} VertexType idxFindStr(ArrayIdx i)
{
return g_init_vexs[i];
} void prt_strings(char *p)
{
char *pos = p;
while (NULL != *pos)
{
printf("%c",*pos);
pos++;
}
printf("\n");
} void prt_strArrays(char *p[])
{
char **pos = p;
while( *pos != NULL)
{
prt_strings(*pos);
pos++;
}
} bool isVexter(char p)
{
if (p>='A' && p<='Z')
{
return true;
}
return false;
} void init_GrapAdjList(GraphAdjList *g,char **str)
{
char **pos = str;
int cnt=;
while (*pos != NULL) //g_input的每行的首指针
{
int i=;
while(**pos != NULL) //g_input的每行字母
{
if(isVexter(**pos)) //判断是否为顶点(我规定‘A’-‘Z’之间为顶点标志)
{
if (i == ) //建立顶点的节点
{
(*g).adjList[cnt].idx = strFindIdx(**pos);
(*g).adjList[cnt].fitstedge = NULL;
i=;
}
else if(i == ) //建立第一个边的节点
{
edgeNode* n = (edgeNode*)malloc(sizeof(edgeNode));
n->idx = strFindIdx(**pos);
n->next = NULL; (*g).adjList[cnt].fitstedge = n;
i=;
}
else //边节点连接到前一个边节点上
{
edgeNode* n = (edgeNode*)malloc(sizeof(edgeNode));
n->idx = strFindIdx(**pos);
n->next = NULL; //first splist
edgeNode *r = (*g).adjList[cnt].fitstedge;
while (r->next != NULL)
{
r = r->next;
}
r->next = n;
}
}
(*pos)++;
}
pos++;
cnt++;
}
(*g).numVextexs = cnt;
} void DFS(GraphAdjList GL,int i)
{
edgeNode *p;
g_visited[i]=true;
printf(" %c ",g_init_vexs[GL.adjList[i].idx]); p = GL.adjList[i].fitstedge;
while(p)
{
if (!g_visited[p->idx])
{
DFS(GL,p->idx);
}
p=p->next;
}
} void DFS_Trvs(GraphAdjList GL)
{
int i;
for (i = ;i<GL.numVextexs;i++)
{
g_visited[i] = false;
}
for (i=;i<GL.numVextexs;i++)
{
if (!g_visited[i])
{
DFS(GL,i);
} }
} int _tmain(int argc, _TCHAR* argv[])
{
GraphAdjList grp;
prt_strArrays(g_input);
init_GrapAdjList(&grp,g_input); DFS_Trvs(grp); getchar();
return ;
}

广度优先遍历:

与邻接矩阵类似。

void BFS(GraphAdjList GL)
{
int i,j;
spQueue Q;
init_Queue(&Q); for (i = ;i < GL.numVextexs;i++)
{
g_visited[i] = false;
}
for (i=;i<GL.numVextexs;i++)
{
if(!g_visited[i])
{
g_visited[i] = true;
printf(" %c ",g_init_vexs[i]);
unshiftQueue(&Q,i); while(!isEmptyQueue(Q))
{
i = shiftQueue(&Q);
edgeNode *p = GL.adjList[i].fitstedge;
while(p != NULL)
{
if (!g_visited[p->idx])
{
g_visited[p->idx]=true;
printf(" %c ",g_init_vexs[p->idx]);
unshiftQueue(&Q,p->idx);
}
p=p->next;
}
}
}
}
}

结构,初始化与广度一样。
多了一个辅助结构-队列。与邻接矩阵中队列一样。

结果:

完整函数:

// grp-tab-bfs.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h> #define MAXVEX 100
#define IFY 65535 typedef char VertexType;
typedef int EdgeType;
typedef int ArrayIdx; //边节点
typedef struct EdgeNode{
ArrayIdx idx;
struct EdgeNode* next;
}edgeNode;
//顶点节点
typedef struct VexNode{
ArrayIdx idx;
edgeNode *fitstedge;
}vexNode; //图的集合:包含了一个顶点数组
typedef struct {
vexNode adjList[MAXVEX];
int numVextexs,numEdges;
}GraphAdjList; typedef int QueueType; bool g_visited[MAXVEX]; VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I'};
char *g_input[] = {
"A->B->F->I",
"B->A->C->I",
"C->B->D",
"D->C->E",
"E->D->F->G->H",
"F->A->E->G",
"G->E->F",
"H->E",
"I->A->B"
}; //==========================================================================
//队列 //队列节点
typedef struct Node {
QueueType data;
struct Node *next;
}QNode,*qQNode; //队列指示
typedef struct {
int length;
qQNode frnt,rear;
}spQueue; void init_Queue(spQueue *Q)
{
(*Q).frnt = NULL;
(*Q).rear = NULL;
(*Q).length = ;
}
bool isEmptyQueue(spQueue Q)
{
if (Q.length == )
{
return true;
}
return false;
}
//进队
void unshiftQueue(spQueue *Q,QueueType elem)
{
//队列空
if (isEmptyQueue(*Q))
{
qQNode n = (qQNode)malloc(sizeof(QNode));
n->data = elem;
n->next = NULL; (*Q).frnt = n;
(*Q).rear = n;
(*Q).length = ;
}
else
{
qQNode n = (qQNode)malloc(sizeof(QNode));
n->data = elem;
n->next = NULL; (*Q).rear->next = n; (*Q).rear = n;
(*Q).length++;
}
} //出队
QueueType shiftQueue(spQueue *Q)
{
if (isEmptyQueue(*Q))
{
printf("Warning:Queue is empty!!!\n");
return NULL;
}
if ((*Q).length == )
{
QueueType sh = (*Q).frnt->data;
(*Q).frnt = NULL;
(*Q).rear = NULL;
(*Q).length = ;
return sh;
}
QueueType sh = (*Q).frnt->data;
(*Q).frnt = (*Q).frnt->next;
(*Q).length--; return sh;
} //打印队列
void prt_que(spQueue que)
{
if (isEmptyQueue(que))
{
return ;
}
qQNode pos = que.frnt;
while(que.rear->next != pos && pos != NULL)
{
printf(" %d ",pos->data);
pos = pos->next;
}
printf("\n");
}
//=============================================================== ArrayIdx strFindIdx(char ch)
{
int i=;
VertexType *p = g_init_vexs;
while(p != NULL)
{
if(*p == ch)
{
return i;
}
p++;
i++;
}
} VertexType idxFindStr(ArrayIdx i)
{
return g_init_vexs[i];
} void prt_strings(char *p)
{
char *pos = p;
while (NULL != *pos)
{
printf("%c",*pos);
pos++;
}
printf("\n");
} void prt_strArrays(char *p[])
{
char **pos = p;
while( *pos != NULL)
{
prt_strings(*pos);
pos++;
}
} bool isVexter(char p)
{
if (p>='A' && p<='Z')
{
return true;
}
return false;
} void init_GrapAdjList(GraphAdjList *g,char **str)
{
char **pos = str;
int cnt=;
while (*pos != NULL) //g_input的每行的首指针
{
int i=;
while(**pos != NULL) //g_input的每行字母
{
if(isVexter(**pos)) //判断是否为顶点(我规定‘A’-‘Z’之间为顶点标志)
{
if (i == ) //建立顶点的节点
{
(*g).adjList[cnt].idx = strFindIdx(**pos);
(*g).adjList[cnt].fitstedge = NULL;
i=;
}
else if(i == ) //建立第一个边的节点
{
edgeNode* n = (edgeNode*)malloc(sizeof(edgeNode));
n->idx = strFindIdx(**pos);
n->next = NULL; (*g).adjList[cnt].fitstedge = n;
i=;
}
else //边节点连接到前一个边节点上
{
edgeNode* n = (edgeNode*)malloc(sizeof(edgeNode));
n->idx = strFindIdx(**pos);
n->next = NULL; //first splist
edgeNode *r = (*g).adjList[cnt].fitstedge;
while (r->next != NULL)
{
r = r->next;
}
r->next = n;
}
}
(*pos)++;
}
pos++;
cnt++;
}
(*g).numVextexs = cnt;
} void BFS(GraphAdjList GL)
{
int i,j;
spQueue Q;
init_Queue(&Q); for (i = ;i < GL.numVextexs;i++)
{
g_visited[i] = false;
}
for (i=;i<GL.numVextexs;i++)
{
if(!g_visited[i])
{
g_visited[i] = true;
printf(" %c ",g_init_vexs[i]);
unshiftQueue(&Q,i); while(!isEmptyQueue(Q))
{
i = shiftQueue(&Q);
edgeNode *p = GL.adjList[i].fitstedge;
while(p != NULL)
{
if (!g_visited[p->idx])
{
g_visited[p->idx]=true;
printf(" %c ",g_init_vexs[p->idx]);
unshiftQueue(&Q,p->idx);
}
p=p->next;
}
}
}
}
} int _tmain(int argc, _TCHAR* argv[])
{
GraphAdjList grp;
prt_strArrays(g_input);
init_GrapAdjList(&grp,g_input);
BFS(grp);
getchar();
return ;
}

这两种是常用的图的遍历算法。时间复杂度在 邻接矩阵结构时候为 O(n2),邻接表结构时候为O(n)。

对于图的存储结构还有:十字链表、多重邻接表等等。

==================================================================

算法学习记录-图(DFS BFS)的更多相关文章

  1. 算法学习记录-图——最短路径之Dijkstra算法

    在网图中,最短路径的概论: 两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点. 维基百科上面的解释: 这个算法是通过为每个顶点 v 保留目前为止所找到的从 ...

  2. 算法学习记录-图——最小生成树之Kruskal算法

    之前的Prim算法是基于顶点查找的算法,而Kruskal则是从边入手. 通俗的讲:就是希望通过 边的权值大小 来寻找最小生成树.(所有的边称为边集合,最小生成树形成的过程中的顶点集合称为W) 选取边集 ...

  3. 算法学习记录-图——应用之关键路径(Critical Path)

    之前我们介绍过,在一个工程中我们关心两个问题: (1)工程是否顺利进行 (2)整个工程最短时间. 之前我们优先关心的是顶点(AOV),同样我们也可以优先关心边(同理有AOE).(Activity On ...

  4. 算法学习记录-图——最小路径之Floyd算法

    floyd算法: 解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包. 设为从到的只以集合中的节点为中间节点的最短路径的长度. 若最短路径经过 ...

  5. 算法学习记录-图——最小生成树之prim算法

    一个连通图的生成树是一个极小的连通子图,它包含图中全部的顶点(n个顶点),但只有n-1条边. 最小生成树:构造连通网的最小代价(最小权值)生成树. prim算法在严蔚敏树上有解释,但是都是数学语言,很 ...

  6. 算法学习记录-图——应用之拓扑排序(Topological Sort)

    这一篇写有向无环图及其它的应用: 清楚概念: 有向无环图(DAG):一个无环的有向图.通俗的讲就是从一个点沿着有向边出发,无论怎么遍历都不会回到出发点上. 有向无环图是描述一项工程或者系统的进行过程的 ...

  7. 算法学习导图+经典排序算法PHP实现

    周末抽时间整理下算法,完整导图可点击下面链接获取. 点我看完整算法导图 八种排序算法的php实现 代码如下 拷贝后可直接运行 先上个运行后的图 代码:(有的自己些的 有的根据网友整理) <?ph ...

  8. Manacher回文串算法学习记录

    FROM:  http://hi.baidu.com/chenwenwen0210/item/482c84396476f0e02f8ec230 #include<stdio.h> #inc ...

  9. 算法系列之图--DFS

    深度优先搜索使用的策略是,只要与可能就在图中尽量“深入”.DFS总是对最近才发现的结点v出发边进行探索,知道该结点的所有出发边都被发现为止.一旦v的所有出发边都被发现了,搜索就回溯到v的前驱结点(v是 ...

随机推荐

  1. UG 常用设置

    Q01:UG制图,添加基本视图之后的中心线怎么去掉? A01:“菜单-->文件-->首选项-->制图-->视图-->公共-->常规-->□带中心线创建”,取消 ...

  2. python学习之串口编程

    # coding=utf-8import serial ser=serial.Serial('com1',9600)ser.write(b"hello")while 1: ser. ...

  3. Linux 安装reids

    1.下载: wget http://download.redis.io/releases/redis-3.0.0.tar.gz 2.解压: .tar.gz 3.安装: cd /redis- make ...

  4. 惊人的CSS和JavaScript动画logos例子

    https://codepen.io/lindell/pen/mEVgJP Stack Overflow logo是我最喜欢的logo之一,因为它非常简单,但易于识别.并且这个片段动画点击预览Stac ...

  5. react之——render prop

    在react “从上至下的数据流原则” 背景下,常规的消息传递机制就是通过prop属性,把父级数据传递给子级,这样一种数据流通模式决定了——数据的接收方子组件要被”硬植入“进数据的数据的给予方父组件, ...

  6. 从零开始利用vue-cli搭建简单音乐网站(五)

    上一篇文章讲到的是如何利用mongoose从数据库读取数据然后更新页面,接下来要实现的就是用户注册登录功能,这个功能涉及到的东西太多了,今天只实现了登录功能,登陆之后更新导航条界面,最后效果如下: 登 ...

  7. JS基础1 — 代码要注意的一些问题

    1.在一对  <script></script>  标签中,有错的js代码,那么该错误代码后面的代码不会执行. 例子:<script> alert("He ...

  8. 【javascript】2017-9-12 腾讯笔试小Q升序算法

    刚做完笔试,腾讯笔试系统真的不友好,作为一个前端,我只会用js写编程题,然而,然而腾讯笔试系统连js输入函数都没给,还不准跳出页面,那个调试结果一直显示错误,我一直找不到错误在哪,心累. 只做了一道笔 ...

  9. JMeter3.2入门使用教程

    JMeter3.2入门使用教程 背景说明 1.1. 背景简介 JMeter是Apache软件基金会下的一个开源项目,纯java开发的应用工具,可以作为进行负载和压力测试的工具来使用.从最开始时被设计成 ...

  10. 在Windows 10删除百度云盘的盘符

    1点击微软图标不放,然后点击R  打开运行命令 2输入  Regedit  进入注册表 3找到以下路径:HKEY_LOCAL_MACHINE  SOFTWARE  Microsoft  Windows ...