7.2.2 图的存储结构
1.多重链表
2.图的邻接矩阵存储结构定义
#define MaxSize 100
typedef struct{
char V[100];//顶点表
int Edge[100][100];//边表
int vexnum,arcnum;//图的当前顶点数和弧数
}MGraph;
3.图的邻接表存储结构定义
typedef struct ArcNode{
int data;
struct ArcNode *next;
}ArcNode;
typedef struct VNode{
int data;
ArcNode *first;
}VNode,AdjList[100];
typedef struct{
AdjList vertices;
int vexnum,arcnum;
}ALGraph;
4.紧缩邻接表
图的基本操作
Adjacent(G,x,y):判断图G是否存在边<x,y>或(x,y).
Neighbors(G,x):列出图G中与结点x邻接的边。
InsertVertex(G,x):在图G中插入顶点x。
DeleteVertex(G,x):从图G中删除顶点x.
AddEdge(G,x,y):如果无向边(x,y)或有向边<x,y>不存在,则向图G中添加该边。
RemoveEdge(Gx,y):如果无向边(x,y)或有向边<x,y>存在,则从图G中删除该边。
FirstNeighbor(G,x):求图G中顶点x的第一个邻接点,若有则返回顶点号。 若x没有邻接或图中不存在x,则返回-1。
NextNeighbor(G,x,y):假设图G中顶点y是顶点x的一个邻接点,返回除y之外顶点x的一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1。
Get_edge_value(G,x,y):获取图G中边(x,y)或<x,y>对应的权值。
Set_edge_value(G,x,y,v):设置图G中边(x,y)或<x,y>对应的权值为v。
7.2.3 图的遍历
1.广度优先搜索BFS
bool visited[G.vexnum];
void BFSTraverse(Graph G)
{
for(int i=0;i<G.vexnum;i++)
visited[i]=false;
InitQueue(Q);
for(int i=0;i<G.vexnum;i++)
{
if(!visited[i])
BFS(G,i)
}
}
void BFS(Graph G,int v)
{
visit[v];
visited[v]=true;
EnQueue(Q,v);
while(!IsEmpty(Q))
{
DeQueue(Q,v);
for(w=FirstNeighbor(Q,v);w>=0;w=NextNeighbor(Q,w))
{
if(!visited[w])
{
visit[w];
visited[w]=true;
EnQueue[Q,w];
}
}
}
}
BFS算法求解单源最短路径问题
void BFS MIN Distance(Graph G,int u){
//d[i]表示从u到i结点的最短路径
for(i=0;i<G.vexnum;++i)
d[i]=∞;//初始化路径长度
visited[u]=TRUE;d[u]=0;
EnQueue(Q,u);
while(!isEmpty(Q)){ //BFS算法主过程
DeQueue(Q,u);//队头元素u出队
for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w))
if(!visited[w]){//w为u的尚未访问的邻接顶点
visited[w]=TRUE;//设已访问标记
d[w]=d[u]+1;//路径长度加1
EnQueue(Q,w);//顶点w入队
}//if
}//while
}
2.深度优先搜索DFS
bool visited[MAX_VERTEX_NUM];//访问标记数组
void DFSTraverse(Graph G)
{
//对图G进行深度优先遍历,访问函数为visit()
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,v);w=NextNeighor(G,v,w))
if(!visited[w]){
DFS(G,w);
}
}
最小生成树算法
通用的最小生成树算法
GENERIC_MST(G){
T=NULL;
while T未形成一棵生成树;
do 找到一条最小代价边(u,v)并且加入T后不会产生回路;
T=T∪(u,v);
}
普利姆Prim算法
void Prim(G,T){
T=∅;//初始化空树
U={w};//添加任一顶点w
while((V-U)!=∅){//若树中不含全部顶点
设(u,v)是使ueU与ve(V-U),且权值最小的边;
T=T∪{(u,v)};//边归入树
U=U∪{v};//顶点归入树
}
克鲁斯卡尔算法Kruskal
void Kruskal(V,T){
T=V;//初始化树T,仅含顶点
nums=n;//连通分量数
while(numS>1){//如果连通分量数大于1
从E中取出权值最小的边(v,u);
if(v和u属于T中不同的连通分量){
T=T∪{(v,u)
};//将此边加入生成树中
nums--;//连通分量数减1
}
}
7.2.4 最短路径
Dijkstra算法求最短路径问题
Floyd算法求各顶点之间最短路径问题
拓扑排序
①从DAG图中选择一个没有前驱的顶点并输出;
②从图中删除该顶点和所有以它为起点的有向边;
③重复①和②直到当前的DAG图为空或者当前图中不存在无前驱的顶点为止。而后一种情况则说明有向图中必然存在环;
bool TopologicalSort(Graph G){
InitStack(S);//通过栈S保存所有入度为0的顶点以便访问
for(int i=0;i<G.vexnum;i++)//找出入度为0的顶点的过程
if(indegree[i]==0)//indegree数组保存了当前所有顶点的入度
Push(S,i);
int count=0;//记录当前访问顶点的个数
while(!isEmpty(S)){//循环2、3,如果为空,则不存在入度为0的顶点了
Pop(S,i);//弹出入度为0的顶点
print[count++]=i;//用来保存拓扑排序的序列
for(p=G.Vertices[i].firstarc;p;p=p->nextarc){
//遍历边表的过程,将p初始化了对应顶点的头指针,然后判断该指针是否为空
v=p->adjvex;//用辅助变量v保存当前边表的内容,也就是该边的另一个端点
if(!(--indegree[v]))//减小了另一个端点的入度,然后如果该顶点的入度为0的话就对其进行压栈操 作,将其保存到栈中
push(S,V);
}
}
if(count<G.vexnum)//如果访问的顶点个数小于该图中的顶点个数,则表示有些顶点没有访问,就返回false,表示拓扑排序失败,
//如果访问了所有的顶点则放回true,表示访问了所有的顶点
return false;
else
return true;
}