4.1 图的遍历 (基于邻接矩阵)
//图的邻接矩阵存储表示
typedef struct{
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
}AMGraph;
4.1.1 BFS广度优先遍历
相当于二叉树的层序遍历
#define MaxVertexNum 100
bool visited[MaxVertexNum];
void BFSTraverse(Graph G){
for(int i=0;i<G.vexnum;i++){
visited[i]=false;
}
InitQueue(Q);
for(int i=0;i<vexnum;i++){
if(!visited[i]) BFS(G,i); //对每个连通分量调用一次BFS算法
}
}
void BFS(Graph G, int v){
visit(v);
visited[v]=true;
EnQueue(Q,v);
while(!QueueIsEmpty(Q)){
DeQueue(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);
}
}
}
}
4.1.2 DFS深度优先遍历
相当于树的先序遍历
#define MaxVertexNum 100
bool visited[MaxVertexNum];
void DFSTraverse(Graph G){
for(v=0;v<G.vexnum;v++) visited[v]=false;
for(v=0;v<G.vexnum;v++){
if(!visited[v]) DFS(G,v);
}
}
void DFS(Graph G, int v){
visit(v);
visited[v]=true;
for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)){
if(!visited[w]) DFS(G,w);
}
}
4.1.3 时空复杂度对比
邻接矩阵 | 邻接表 | |
---|---|---|
BFS | 时:O(V^2) | 时:O(V+E) 空:O(n) |
DFS | 时:O(V^2) | 时:O(V+E) 空:O(n) |
4.2 图的遍历 (基于邻接表)
//图的邻接表
typedef struct ArcNode{ //边结点
int adjvex; //该边所指向的顶点的位置
struct ArcNode *nextarc; //指向下一条边的指针
}ArcNode;
typedef struct VNode{
VerTexType data; //顶点信息
ArcNode *firstarc; //指向第一条依附该顶点的边的指针
}VNode, AdjList[MVNum]; //AdjList表示邻接表类型
typedef struct{
AdjList vertices; //邻接表
int vexnum, arcnum; //图的当前顶点数和边数
}ALGraph;
4.2.1 BFS广度优先遍历
bool visited[MaxVertexNum]; //访问标志数组,其初值为"false"
void BFS(ALGraph G, int v){
cout<<G.vertices[v].data;
visited[v]=true;
EnQueue(Q,v);
while(!QueueIsEmpty(Q)){
DeQueue(Q,v);
ArcNode *p = G.vertices[v].firstarc;
while(p!=NULL){
int w=p->adjvex;
if(!visited(w)){
visit(w);
visited[w]=true;
EnQueue(Q,w);
}
p=p->nextarc;
}
}
}
4.2.2 DFS深度优先遍历
void DFS(ALGraph G, int v){ //图G为邻接表类型
cout << G.vertices[v].data;
visited[v] = true; //访问第v个顶点,并置访问标志数组相应分量值为true
ArcNode *p = G.vertices[v].firstarc; //p指向v的边链表的第一个边结点
while(p != NULL){ //边结点非空
int w = p->adjvex; //表示w是v的邻接点
if(!visited[w]) DFS(G, w); //如果w未访问,则递归调用DFS
p = p->nextarc; //p指向下一个边结点
}
}
4.3 图的应用
4.3.1 prim算法代码(最小生成树)
int Min(AMGraph G){
//返回权值最小的点
int i;
int index = -1;
int min = MaxInt;
for(i = 0 ; i < G.vexnum ; ++i){
if(min > closedge[i].lowcost && closedge[i].lowcost != 0){
min = closedge[i].lowcost;
index = i;
}
}//for
return index;
}
void MiniSpanTree_Prim(AMGraph G, VerTexType u){
//无向网G以邻接矩阵形式存储,从顶点u出发构造G的最小生成树T,输出T的各条边
int k , j , i;
VerTexType u0 , v0;
k =LocateVex(G, u); //k为顶点u的下标
for(j = 0; j < G.vexnum; ++j){ //对V-U的每一个顶点vi,初始化closedge[i]
if(j != k){
closedge[j].adjvex = u;
closedge[j].lowcost = G.arcs[k][j]; //{adjvex, lowcost}
}//if
}//for
closedge[k].lowcost = 0; //初始,U = {u}
for(i = 1; i < G.vexnum; ++i){ //选择其余n-1个顶点,生成n-1条边(n= G.vexnum)
k = Min(G);
//求出T的下一个结点:第k个顶点,closedge[k]中存有当前最小边
u0 = closedge[k].adjvex; //u0为最小边的一个顶点,u0∈U
v0 = G.vexs[k]; //v0为最小边的另一个顶点,v0∈V-U
cout << "边 " <<u0 << "--->" << v0 << endl; //输出当前的最小边(u0, v0)
closedge[k].lowcost = 0; //第k个顶点并入U集
for(j = 0; j < G.vexnum; ++j)
if(G.arcs[k][j] < closedge[j].lowcost){ //新顶点并入U后重新选择最小边
closedge[j].adjvex = G.vexs[k];
closedge[j].lowcost = G.arcs[k][j];
}//if
}//for
}