6.1 图的逻辑结构
6.1.1 图的定义和基本术语
数据元素称为顶点。
1、 图的定义
图是由顶点的有穷非空集合和顶点之间边的集合组成。
如果图的任意两个顶点之间的边都是无向边,则称该图为无向图;否则称有向图。
2、 图的基本术语
简单图
若不存在顶点到其自身的边,且同一条边不重复出现,则称为简单图。
无向完全图:任意两个顶点之间都存在边。含n个顶点的无向完全图有n*(n-1)/2条边。
有向完全图:任意两顶点之间都存在方向互为相反的两条弧。含n个顶点的有向完全图有n*(n-1)条边。
无向图中顶点的度:依附于该顶点的边的个数。具有n个顶点e条边 ,度=2e.
有向图中顶点的度:以该顶点为弧头的弧的个数。具有n个顶点e条边,度=e.
简单路径:顶点不重复出现的路径。
简单回路:除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路。
子图:
连通图和连通分量
生成树、生成森林
6.1.2 图的抽象数据类型定义
6.1.3图的遍历操作
1、深度优先遍历
(1)访问顶点V;
(2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历
(3)重复上述两步,直至图中所有的顶点都被访问到。
2、 广度优先遍历
(1) 访问顶点v
(2) 依次访问v的各个未被访问的邻接点v1,,,vk
(3) 分别从v1,,,vk出发依次访问它们未被访问的邻接点,并使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问。直至图中所有的顶点都被访问到。
6.2 图的存储结构及实现
6.2.1邻接矩阵
在C++中的模板机制
Const int MaxSize=10;
Template<class T>
Class MGraph
{
Public:
MGraph(T a[],int n,int e);
~MGraph(){ }
Void DFSTraverse(int v);
Void BFSTraverse(int v);
Private:
T vertex[MaxSize];
Int arc[MaxSize];
Int vertexNum,arcNum;
}
1、 构造函数
template<class T>
MGraph<T>::MGraph(T a[],int n,int e)
{
vertexNum=n;arcNum=e;
for(i=0;i<vertexNum;i++)
vertex[i]=a[i];
for(i=0;i<vertexNum;i++)
for(j=0;j<vertexNum;j++)
arc[i][j]=0;
for(k=0;k<arcNum;k++)
{
cin>>i>>j;
arc[i][j]=1;arc[j][i]=1;
}
}
2、深度优先遍历
template<class T>
void MGraph<T>::DFSTraverse(int v)
{
cout<<vertex[v];visited[v]=1;
for(int j=0;j<vertexNum;j++)
if(arc[v][j]==1&&visited[j]==0)
DFSTraverse(j);
}
3、广度优先遍历template<class T>
void MGraph<T>::BFSTraverse(int v)
{
int front=-1,rear=-1;
cout<<vertex[v];visited[v]=1;Q[++rear]=v;
while(front!=rear)
{
v=Q[++front];
for(int j=0;j<vertexNum; j++)
if(arc[v][j]==1&&visited[j]==0)
{
cout<<vertex[j];visited[j]=1;Q[++rear]=j;
}
}
}
6.2.2邻接表
邻接表是一种顺序存储与链接存储相结合的存储方法,类似于树的孩子链表表示方法。
存在两种节点结构:
用C++语言中的结构体类型描述上述结点。
struct ArcNode
{
int adjvex;
ArcNode *next;
};
template <class T>
struct VertexNode
{
T vertex;
ArcNode *firstedge;
};
用C++语言中的类实现基于邻接表存储结构下图的抽象数据类型定义:
class ALGraph
{
public:
ALGraph(T a[],int n,int e);
~ALGraph();
void DFSTraverse(int v);
void BFSTraverse(int v);
private:
VertexNode<T>adjlist[MaxSize];
int vertexNum,arcNum;
};
1、构造函数算法ALGraph
template<class T>
ALGraph<T>::ALGraph(T a[],int n,int e)
{
vertexNum=n;arcNum=e;
for(i=0;i<vertexNum;i++)
{
adjlist[i].vertex=a[i];
adjlist[i].firstedge=NULL;
}
for(k=0;k<arcNum;k++)
{
cin>>i>>j;
s=new ArcNode;s->adjvex=j;
s->next=adjlist[i].firstedge;
adjlist[i].firstedge=s;
}
}
2、深度优先遍历算法DFSTraverse
template<class T>
void ALGraph<T>::DFSTraverse(int v)
{
ArcNode *p=NULL;int j;
cout<<adjlist[v].vertex;vistited[v]=1;
p=adjlist[v].firstedge;
while(p!=NULL)
{
j=p->adjvex;
if(visited[j]==0) DFSTraverse(j);
p=p->next;
}
}
3、广度优先遍历算法BFSTraverse
template<class T>
void ALGraph<T>::BFSTraverse(int v)
{
int Q[MaxSize];
int front=-1,rear=-1;
ArcNode *p=NULL;
cout<<adjlist[v].vertex;visited[v]=1;Q[++rear]=v;
while(front!=rear)
{
v=Q[++front];
p=adjlist[v].firstedge;
while(p!=NULL)
{
int j=p->adjvex;
if(visited[j]==0)
{
cout<<adjlist[j].vertex;visited[j]=1;Q[++rear]=j;
}
p=p->next;
}
}
}
6.3 最小生成树
设G=(V,E)是一个无向连通网,生成树上各边的权值之和称为该生成树的代价,在G的所有生成树中,代价最小的生成树称为最小生成树。
6.3.1 Prim 算法
Void Prim(MGraph G)
{
For(i=1;i<G.vertexNum;i++)
{
shortEdge[i] .lowcost=G.arc[0][i];
shortEdge[i].adjvex=0;
}
shortEdge[0].lowcost=0;
For(i=1;i<G.vertexNum;i++)
{
K=MinEdge(shorEdge,G.vertexNum)
Cout<<”(“<<k<<shortEdge[k].adjvex<<”)”<<shortEdge[k].lowcost;
shortEdge[k].lowcost=0;
For(j=1;j<G.vertexNum;j++)
If G.arc[k][j]<shortEdge[j].lowcost
{
shortEdge[j].lowcost=G.arc[k][j];
shortEdge[j].adjvex=k;
}
}
}
6.3.2 Kruskal 算法
Void Kruskal(EdgeGraph G)
{
For(i=0;i<G.vertexNum;i++)
Parent[i]=-1;
For(num=0,i=0;i<G.edgeNum;i++)
{
Vex1=FindRoot(parent,G.edge[i].from);
Vex2=FindRoot(parent,G.edge[i].to);
If(vex1!=vex2)
{
Cout<<”(“<<G.edge[i].from<<G.edge[i].to<<”)”<<endl;
Parent[vex2]=vex1;
Num++;
If(num==n-1) return;
}
}
}
Int FindRoot(int parent[],int v)
{
T=v;
If(parent[t]>-1) t=parent[t];
Return t;
}
6.4 最短路径
最短路径是指两顶点之间经历的边数最小的路径,路径上的第一个顶点称为源点,最后一个顶点称为终点。
Dijkstra算法
Void Dijkstra(MGraph G,int v)
{
For(i=0;i,G.vertexNum;i++)
{
Dist[i]=G.arc[v][i];
If(dist[i]!=ɷ)path[i]=G.vertex[v]+G.vertex[i];
Else path[i]=” “;
}
S[0]=v;
Dist[v]=0;
Num=1;
While(num<G.vertexNum)
{
For(k=0,i=0;i<G.vertexNum;i++)
If((dist[i]!0)&&(dist[i]<dist[k])) k=i;
Cout<<dist[k]<<path[k];
S[num++}=k;
For(i=0;i<G.vertexNum;i++)
If(dist[i]>dist[k]+G.arc[k][i])
{
dist[i]=dist[k]+G.arc[k][i];
path[i]=path[k]+G.vertex[i];
}
Dist[k]=0;
}
}
6.4.2 Floyd 算法
6.5 有向无环图
6.5.1 AOV 网与拓扑排序
在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,称这样的有向图为顶点表示活动的网,简称AOV网。
基本思想是:
1)从AOV网中选择一个没有前驱的顶点并且输出它;
2) 从AOV网中删去该顶点,并且删去所有以该顶点为尾的弧;
3)重复上述两步,直到全部顶点都被输出,或AOV网中不存在没有前驱的顶点。
伪代码:
拓扑排序算法TopSort
void TopSort(ALGraph G)
{
top=-1;count=0;
for(i=0;i<G.vertexNum;i++)
if(G.adjlist[i].in==0)s[++top]=i;
while(top=-1)
{
j=s[top--];
cout<<G.adjlist[j].vertex;count++;
p=G.adjlist[j].firstedge;
while(p!=NULL)
{
k=p->adjvex;
G.adjlist[k].in--;
if(G.adjlist[k].in==0) S[++top]=k;
p=p->next;
}
}
if(count<G.vertexNum) cout<<"有回路";
}
本章总结