目录
图的存储结构
邻接矩阵
typedef struct
{
int no; //顶点编号
char info; //顶点其他信息(一般不用)
}VertexType; //顶点类型
typedef struct //图的定义
{
int edges[maxSize][maxSize]; //邻接矩阵定义
int n,e; //顶点数和边数
VertexType vex[maxSize]; //存放结点信息
}MGraph; //图的邻接矩阵类型
邻接表
typedef struct ArcNode //边定义
{
int adjvex; //该边所指向结点
struct ArcNode *nextarc; //指向下一条边的指针
int info; //边的其他信息(如权值)
}ArcNode;
typedef struct //点定义
{
char data; //顶点信息
ArcNode *firstarc; //指向第一条边的指针
}VNode;
typedef struct //邻接表定义
{
VNode adjlist[maxSize]; //邻接表
int n,e; //顶点数和边数
}AGraph;
图的遍历算法
图的深度优先算法
以邻接表为存储结构的图的深度优先搜索遍历算法(天勤)
int visit[maxSize]; // 记录顶点是否被访问
void DFS(AGraph *G, int v)
{
ArcNode *p;
visit[v]=1; // 设置已访问标记
Visit(v); // 访问v
p=G->adjlist[v].firstarc; //指向顶点的第一条边
while(p!=NULL)
{
if(visit[p->adjvex]==0) // 若顶点未访问,则递归它
DFS(G,p->adjvex);
p=p->nextarc; // p指向顶点v的下一条边的终点
}
}
//若为非联通图,外套一层循环
void dfs(AGraph *g)
{
int i;
for(i=0;i<g->n;++i)
if(visit[i]=0)
DFS(g,i);
}
以邻接表为存储结构的图的广度优先搜索遍历算法(王道)
bool visited[MAX_VERTEX_NUM]; // 标记访问数组
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) { // 从顶点 v 出发,深度优先遍历图 G
visit(v); // 访问顶点 v
visited[v] = TRUE; // 标记已访问过该顶点
for(w = FirstNeighbor(G,v);w >= 0; w = NextNeighor(G,v,w))
if(!visited(w))
DFS(G,w);
}
图的广度优先算法
以邻接表为存储结构的图的广度优先搜索遍历算法(天勤)
void BFS(AGraph *G, int v, int visit[maxSize])
{
ArcNode *p;
int que[maxSize], front=0, rear=0; // 队列定义
int j;
Visit(v); // 任意访问顶点v的函数
visit[v]=1;
rear=(rear+1)%maxSize;
que[rear]=v; // 进队
while(front!=rear) // 队空的时候说明遍历完成
{
front=(front+1)%maxSize;
j=que[front];
p=G->adjlist[j].firstarc; // p指向出队顶点j的第一条边
while(p!=NULL)
{
if(visit[p->adjvex]==0) // 当前结点未被访问,进队
{
Visit(p->adjvex);
visit[p->adjvex]=1;
rear=(rear+1)%maxSize;
que[rear]=p->adjvex; // 顶点进队
}
p=p->nextarc; // p指向j的下一条边
}
}
}
//如果为非联通图,外套循环
void bfs(AGraph *g)
{
int i;
for(i=0;i<g->n;++i)
if(visit[i]==0)
BFS(g,i,visit);
}
以邻接表为存储结构的图的广度优先搜索遍历算法(王道)
bool visited[MAX_VERTEX_NUM]; // 标记访问数组
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
BFS(G,i); // 对没有访问过的顶点进行BFS遍历
}
void BFS(Graph G,int v) // 从顶点 v 出发,进行广度优先遍历
{
visit(v);
visited[v] = TRUE; // 标记顶点 v 已经访问过
EnQueue(Q,v); // 将顶点 v 进行入队
while(!isEmpty(Q)) {
DeQueue(Q,v); // 顶点 v 出队
for(w = FirstNeighbor(G,v); w >= 0; w = NextNeighbor(G,v,w)){//检测 v 所有的邻接点
if(!visited[w]){
visit(w);
visited[w] = TRUE;
EnQueue(Q,w);
}
}
}
}
西工大期末04-05 有向图邻接链表 DFS非递归
void DFS(AGraph *g,int v)
{
ArcNode *p;
int stack[maxSize],top=-1; //定义一个栈来几率访问过程中的顶点
int i,k;
int visit[maxSize];
for(i=0;i<g->n;++i) //g->n为图中的顶点总数
visit[i]=0; //初始化数组
visit(v); //包含对顶点v的各种操作
visit[v]=1; //标记定义已被访问
stack[++top]=v; //起始顶点入栈
while(top!=-1)
{
k=stack[top]; //取栈顶元素
p=g->adjlist[k].firstarc; //p指向该顶点的第一条边
while(p!=NULL&&visit[p->adjvex]==1) //找到当前顶点第一个未被访问的邻接顶点
p=p->nextarc;
if(p==NULL) //如果p为空,代表当前顶点的所有邻接顶点都被访问过,当前顶点出栈
--top;
else //否则访问邻接点,并入栈
{
visit(p->adjvex);
visit[p->adjvex]=1;
stack[++top]=p->adjvex;
}
}
}
西工大期末09-10 无向图邻接矩阵 DFS非递归
bool visited[vexnum]; // 标记访问数组
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) // 从顶点 v 出发,深度优先遍历图 G
{
int w;
initstack(s); //用栈实现递归
Push(s,v); //将顶点v入栈
visited[v] = TRUE; // 标记已访问过该顶点
while(!IsEmpty(s)) //栈不空时循环
{
k=Pop(s);
visit(k);
for(w = 0;w < G.vexnum;w ++)
{
if(G.Edge[k][w] == 1 && !visited(w))
{
Push(s,w);
visited[w] = TRUE;
}
}
}
}
西工大07考研邻接矩阵DFS递归
bool visited[vexnum];
void DFS(Graph G,int v)
{
visit(v);
visit[v]=true;
for(w=0;w<G.vexnum;w++)
{
if(G.edge[v][w] ==1 && !visited[w])
{
DFS(G,w);
}
}
}
最小生成树
普利姆算法(Prim)
void Prim(MGraph g, int v0, int &sum)
{
int lowcost[maxSize],vset[maxSize], v;
//lowcost存放当前生成树到剩余各顶点最短边权值,vset表示顶点是否并入树中
int i, j, k, min;
v=v0;
for(i = 0; i < g.n; i++)
{
lowcost[i] = g.edges[v0][i];
vset[i] = 0; //初始化数组
}
vset[v0] = 1; //将v0并入树中
sum=0; //sum清零用来累计树的权值
for(i = 0; i < g.n-1; i++) //用于选出侯选边中的最小者
{
min = INF; //INF是已经定义过的一个巨大值
for(j = 0; j < g.n; j++)
if(vset[j]==0 && lowcost[j]<min) //选出当前生成树到其余顶点最短边中的最短的一条
{
min = lowcost[j];
k = j;
}
vset[k] = 1;
v=k;
sum += min;
for(j = 0; j < g.n; j++) //更新侯选边
if(vset[j] == 0 && g.edges[v][j] < lowcost[j])
lowcost[j] = g.edges[v][j];
}
}
克鲁斯卡尔算法
void Kruskal(MGraph g, int &sum, Road road[])
{ int i, a, b;
sum = 0;
for(i = 0; i < g.n; i++) //将各顶点设置为不同的连通分量
v[i] = i;
sort(road,g.e); //对所有边进行排序
for(i = 0; i < g.e; i++)
{
a = getRoot(road[i].a); //使a等于边的始点所在的连通分量
b = getRoot(road[i].b); //使b等于边的终点所在的连通分量
if(a != b) //如果a、b非同一连通分量
{
v[a] = b; //将a并入b
sum += road[i].w; //权值累计
}
}
}
拓扑序列
bool TopologicalSort(Graph G)
{
InitStack(S); //初始化栈,将一开始入度为零的顶点入栈
int i;
for(i = 0;i < G.xevnum;++i){
if(indegree[i] == 0)
Push(S,i);
}
int count = 0;
while(!IsEmpty(S)){ //当栈不为空,说明还有顶点可以加入排序
Pop(S,i);
print[count ++] = i; //将入度为0的结点放入打印数组中
for(ArcNode *p = G.vertices[i].firstarc; p; p = p -> nextarc){ //删除顶点i的出边
v = p -> adjvex;
if(!(--indegree[v])) //更新入度为0的数组,将数组内点入栈
Push(S,v);
}
}
if(count != G.vexnum)
return false; //检查打印数组中元素数是否与图顶点一致
else
return true;
}