69,382
社区成员
发帖
与我相关
我的任务
分享
#define MAX_VERTEX_NUM 20
#define VISITED 1
#define UNVIST 0
typedef char VertexType;
typedef int InfoType;
#define OK 1
#define ERROR 0
#define NFOUND -1
#define DG 0 //有向图
#define UDG 1 //无向图
typedef struct ArcNode //弧节点的结构
{
int adjvex; //该弧指向的顶点的位置(下标)
struct ArcNode *nextarc;
InfoType *info;
}ArcNode;
typedef struct VNode //顶点节点的结构
{
VertexType data;
ArcNode *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];
typedef struct //图的邻接表结构定义
{
AdjList vertex;
int vexnum,arcnum;
int kind;
}ALGraph;
int LocateVex(ALGraph G,VertexType v) //返回v节点在图中的位置,即下标.
{
int i;
for(i=0 ; i<G.vexnum ; ++i)
if( v == G.vertex[i].data)
return i;
return NFOUND;
}
void CreatG(ALGraph &G)
{
ArcNode *p;
int i,j,k;
int isWeight;
VertexType v1,v2;
cout <<"enter vernum:"; cin>>G.vexnum; //输入顶点个数
cout <<"enter arcnum:"; cin>>G.arcnum; //输入弧的数目
cout <<"enter graph kind:(0-DG ; 1-UDG):"; cin>>G.kind; //输入创建图的类型
cout <<"创建的图是否带有权值?(0-不带,1-带):"; cin>>isWeight;
cout << endl;
for(i=0; i <G.vexnum ; ++i) //输入每个顶点的数据
{
cout << "enter vertex["<<i+1<<"]:";
cin >>G.vertex[i].data;
G.vertex[i].firstarc = NULL;
}
for(k=0; k <G.arcnum ; ++k) //建图
{
cout << "#####enter origin vertex:"; cin>>v1; //起点
cout << "enter destination vertex:"; cin>>v2; //终点
i = LocateVex(G,v1); j = LocateVex(G,v2);
p = new ArcNode;
p->adjvex = j;
if(isWeight) //如果带权值就输入该弧的权值
{
p->info = new InfoType;
cout << "############enter weight:";
cin >> *p->info;
}
p->nextarc = G.vertex[i].firstarc;
G.vertex[i].firstarc = p;
if(G.kind == UDG) //如果是无向图,建立逆向链接
{
p = new ArcNode;
p->adjvex = i;
p->nextarc = G.vertex[j].firstarc;
G.vertex[j].firstarc = p;
}
}
}//建图
求kruskal最小生成数算法,还有遍历该生成树的算法.
void MakeSet(ALGraph G,EdgeType *edge,int *parent) //将图中所有边的信息放在集合edge中
{
int i,j;
int *isPutEdge = new int[G.arcnum]; //对于无向图,防止重复读取相同的边
ArcNode *p;
for(i=0; i<G.vexnum ; ++i)
isPutEdge[i] = 1;
for(i=0,j=0 ; i<G.vexnum; ++i) //将图中所有的边的信息收入到edge中 类似MAKE-SET操作
{
p = G.vertex[i].firstarc;
while(p)
{
edge[j].vex1 = i;
if(isPutEdge[p->adjvex]) //判断vertex[p->adjvex]的所有连通量是否已被包含到edge中,防止取到相同的边
{
edge[j].vex2 = p->adjvex;
edge[j].weight = *(p->info);
++j;
}
p=p->nextarc;
}
isPutEdge[i] = 0; //与vertex[i]相关的边已被全部录入到edge中,
}
}
void Sort(EdgeType *edge,int n) //对集合edge中的元素按权值大小进行升序排列
{
int i,j;
EdgeType tmp;
for(i =1; i<n; ++i)
{
for(j=i; j>0; --j)
if(edge[j].weight < edge[j-1].weight)
{
tmp = edge[j];
edge[j] = edge[j-1];
edge[j-1] = tmp;
}
}
}
int FindSet(int *parent,int v)
{
if(parent[v] == -1)
return v;
else
FindSet(parent, parent[v]);
}
void Union(int *parent, int v1,int v2)
{
int i,j;
i = FindSet(parent,v1);
j = FindSet(parent,v2);
if(parent[i] == -1 && parent[j] == -1) //如果该边的两个顶点分属不同的树,则将这两颗树合并.
{
parent[j] = i;
}
else if(i!=j)
{
if(parent[v2] == -1) //判断顶点v2是否有为子树,若是则让v1成为v2的子树,否则v2为v1的子树
parent[v1] = v2;
else
parent[v2] = v1;
}
}
void print(ALGraph G,int *parent) //按层次遍历生成树的方式输出kruskal最小生成树
{
int i,j,k;
int *visited = new int[G.vexnum];
Queue Q;
InitQ(Q);
for(i=0; i<G.vexnum ; ++i)
visited[i] = UNVIST;
for(i=0 ; i<G.vexnum ; ++i)
if(parent[i] == -1) break;
EnQueue(Q,i);
while(!IsEmpty(Q))
{
for(j=0 ; j<G.vexnum ; ++j)
{
if(parent[j] == i)
if(!visited[j])
EnQueue(Q,j);
}
DeQueue(Q,k);
if(!visited[k])
{
i = k;
cout << G.vertex[k].data<<" ";
visited[k] = VISITED;
}
}
}
void Kruskal(ALGraph G)
{
int *parent = new int[G.vexnum];
EdgeType *edge = new EdgeType[G.arcnum]; //存放边的信息
int i,j,k,n;
ArcNode *p;
for(i=0 ; i<G.vexnum ; ++i)
parent[i] = -1;
MakeSet(G,edge,parent); //建立边的集合edge;
Sort(edge,G.arcnum); //对集合edge按照权值大小进行升序排列;
for(i=0; i< G.arcnum; ++i)
{
k = FindSet(parent,edge[i].vex1);
j = FindSet(parent,edge[i].vex2);
if( k!= j)
{
Union(parent,edge[i].vex1, edge[i].vex2); //将边edge[i]收入到子树中
cout << G.vertex[edge[i].vex1].data <<"---" <<G.vertex[edge[i].vex2].data <<" weight="
<< edge[i].weight<<endl; //输出边的2个顶点及权值
}
}
cout <<endl<<endl;
print(G,parent);
}
Union()里面加了将2颗树合并起来的判断,....
明天结帖,谢谢1楼和7楼,给了些提示
搞的差不多了,还有一点小问题...
typedef struct //最小生成树用到的,记录顶点和之间的权值
{
int vex1; //2个顶点
int vex2;
int weight; //边的权值
}EdgeType;
void MakeSet(ALGraph G,EdgeType *edge,int *parent) //将图中所有边的信息放在集合edge中
{
int i,j;
int *isPutEdge = new int[G.arcnum]; //对于无向图,防止重复读取相同的边
ArcNode *p;
for(i=0; i<G.vexnum ; ++i)
isPutEdge[i] = 1;
for(i=0,j=0 ; i<G.vexnum; ++i) //将图中所有的边的信息收入到edge中 类似MAKE-SET操作
{
p = G.vertex[i].firstarc;
while(p)
{
edge[j].vex1 = i;
if(isPutEdge[p->adjvex]) //判断vertex[p->adjvex]的所有连通量是否已被包含到edge中,防止取到相同的边
{
edge[j].vex2 = p->adjvex;
edge[j].weight = *(p->info);
++j;
}
p=p->nextarc;
}
isPutEdge[i] = 0; //与vertex[i]相关的边已被全部录入到edge中,
}
}
void Sort(EdgeType *edge,int n) //对集合edge中的元素按权值大小进行升序排列
{
int i,j;
EdgeType tmp;
for(i =1; i<n; ++i)
{
for(j=i; j>0; --j)
if(edge[j].weight < edge[j-1].weight)
{
tmp = edge[j];
edge[j] = edge[j-1];
edge[j-1] = tmp;
}
}
}
int FindSet(int *parent,int v)
{
if(parent[v] == -1)
return v;
else
FindSet(parent, parent[v]);
}
void print(ALGraph G,int *parent) //才用层次遍历生成树的方式输出
{
int i,j,k;
int *visited = new int[G.vexnum];
Queue Q;
InitQ(Q);
for(i=0; i<G.vexnum ; ++i)
visited[i] = UNVIST;
for(i=0 ; i<G.vexnum ; ++i)
if(parent[i] == -1) break;
EnQueue(Q,i);
while(!IsEmpty(Q))
{
for(j=0 ; j<G.vexnum ; ++j)
{
if(parent[j] == i)
if(!visited[j])
EnQueue(Q,j);
}
DeQueue(Q,k);
if(!visited[k])
{
i = k;
cout << G.vertex[k].data<<" ";
visited[k] = VISITED;
}
}
}
void Kruskal(ALGraph G)
{
int *parent = new int[G.vexnum];
EdgeType *edge = new EdgeType[G.arcnum]; //存放边的信息
int i,j,k,n;
ArcNode *p;
for(i=0 ; i<G.vexnum ; ++i)
parent[i] = -1;
MakeSet(G,edge,parent); //建立边的集合edge;
Sort(edge,G.arcnum); //对集合edge按照权值大小进行升序排列;
for(i=0; i< G.arcnum; ++i)
{
k = FindSet(parent,edge[i].vex1);
j = FindSet(parent,edge[i].vex2);
if( k!= j)
{
if(parent[edge[i].vex2] == -1) //核心部分 这里怎么写才合适?
parent[edge[i].vex2] = edge[i].vex1;
else
parent[edge[i].vex1] = edge[i].vex2;
cout << G.vertex[edge[i].vex1].data <<"---" <<G.vertex[edge[i].vex2].data <<" weight="
<< edge[i].weight<<endl; //输出边的2个顶点及权值
}
}
cout <<endl<<endl;
print(G,parent);
}
如果建立这样的一个图 : a (3) - b (5) -d
a (7) - c (4) -d
a (6) -d
无相图,()里面的是权值,我用上面的代码跑下来的结果是
------------------
a---b weight=3
c---d weight=4
b---d weight=5
a---d weight=6
这个图生成最小树的话 只要3 4 5这3条边就够了,可是又把6这条边收进去了, 怎么改我上面的代码才可以?
搞的差不多了,还有一点小问题...
typedef struct //最小生成树用到的,记录顶点和之间的权值
{
int vex1; //2个顶点
int vex2;
int weight; //边的权值
}EdgeType;
void MakeSet(ALGraph G,EdgeType *edge,int *parent) //将图中所有边的信息放在集合edge中
{
int i,j;
int *isPutEdge = new int[G.arcnum]; //对于无向图,防止重复读取相同的边
ArcNode *p;
for(i=0; i<G.vexnum ; ++i)
isPutEdge[i] = 1;
for(i=0,j=0 ; i<G.vexnum; ++i) //将图中所有的边的信息收入到edge中 类似MAKE-SET操作
{
p = G.vertex[i].firstarc;
while(p)
{
edge[j].vex1 = i;
if(isPutEdge[p->adjvex]) //判断vertex[p->adjvex]的所有连通量是否已被包含到edge中,防止取到相同的边
{
edge[j].vex2 = p->adjvex;
edge[j].weight = *(p->info);
++j;
}
p=p->nextarc;
}
isPutEdge[i] = 0; //与vertex[i]相关的边已被全部录入到edge中,
}
}
void Sort(EdgeType *edge,int n) //对集合edge中的元素按权值大小进行升序排列
{
int i,j;
EdgeType tmp;
for(i =1; i<n; ++i)
{
for(j=i; j>0; --j)
if(edge[j].weight < edge[j-1].weight)
{
tmp = edge[j];
edge[j] = edge[j-1];
edge[j-1] = tmp;
}
}
}
int FindSet(int *parent,int v)
{
if(parent[v] == -1)
return v;
else
FindSet(parent, parent[v]);
}
void print(ALGraph G,int *parent) //才用层次遍历生成树的方式输出
{
int i,j,k;
int *visited = new int[G.vexnum];
Queue Q;
InitQ(Q);
for(i=0; i<G.vexnum ; ++i)
visited[i] = UNVIST;
for(i=0 ; i<G.vexnum ; ++i)
if(parent[i] == -1) break;
EnQueue(Q,i);
while(!IsEmpty(Q))
{
for(j=0 ; j<G.vexnum ; ++j)
{
if(parent[j] == i)
if(!visited[j])
EnQueue(Q,j);
}
DeQueue(Q,k);
if(!visited[k])
{
i = k;
cout << G.vertex[k].data<<" ";
visited[k] = VISITED;
}
}
}
void Kruskal(ALGraph G)
{
int *parent = new int[G.vexnum];
EdgeType *edge = new EdgeType[G.arcnum]; //存放边的信息
int i,j,k,n;
ArcNode *p;
for(i=0 ; i<G.vexnum ; ++i)
parent[i] = -1;
MakeSet(G,edge,parent); //建立边的集合edge;
Sort(edge,G.arcnum); //对集合edge按照权值大小进行升序排列;
for(i=0; i< G.arcnum; ++i)
{
k = FindSet(parent,edge[i].vex1);
j = FindSet(parent,edge[i].vex2);
if( k!= j)
{
if(parent[edge[i].vex2] == -1) //核心部分 这里怎么写才合适?
parent[edge[i].vex2] = edge[i].vex1;
else
parent[edge[i].vex1] = edge[i].vex2;
cout << G.vertex[edge[i].vex1].data <<"---" <<G.vertex[edge[i].vex2].data <<" weight="
<< edge[i].weight<<endl; //输出边的2个顶点及权值
}
}
cout <<endl<<endl;
print(G,parent);
}
如果建立这样的一个图 : a (3) - b (5) -d
a (7) - c (4) -d
a (6) -d
无相图,()里面的是权值,我用上面的代码跑下来的结果是
------------------
a---b weight=3
c---d weight=4
b---d weight=5
a---d weight=6
这个图生成最小树的话 只要3 4 5这3条边就够了,可是又把6这条边收进去了, 怎么改我上面的代码才可以?
/*
Name:最小生成树kruskal算法
Author:wujilin
Description:用邻接矩阵做图
Date: 21-07-06 23:07
Copyright:wujilin
*/
#include<stdio.h>
#include<stdlib.h>
#define M 20
#define MAX 20
typedef struct
{
int begin;
int end;
int weight;
}edge;
typedef struct
{
int adj;
int weight;
}AdjMatrix[MAX][MAX];
typedef struct
{
AdjMatrix arc;
int vexnum, arcnum;
}MGraph;
void CreatGraph(MGraph *);//函数申明
void sort(edge* ,MGraph *);
void MiniSpanTree(MGraph *);
int Find(int *, int );
void Swapn(edge *, int, int);
void CreatGraph(MGraph *G)//构件图
{
int i, j,n, m;
printf(\"请输入边数和顶点数:\");
scanf(\"%d %d\",&G->arcnum,&G->vexnum);
for (i = 1; i <= G->vexnum; i++)//初始化图
{
for ( j = 1; j <= G->vexnum; j++)
{
G->arc[i][j].adj = G->arc[j][i].adj = 0;
}
}
for ( i = 1; i <= G->arcnum; i++)//输入边和权值
{
printf(\"\\n请输入有边的2个顶点\");
scanf(\"%d %d\",&n,&m);
while(n < 0 || n > G->vexnum || m < 0 || n > G->vexnum)
{
printf(\"输入的数字不符合要求 请重新输入:\");
scanf(\"%d%d\",&n,&m);
}
G->arc[n][m].adj = G->arc[m][n].adj = 1;
getchar();
printf(\"\\n请输入%d与%d之间的权值:\", n, m);
scanf(\"%d\",&G->arc[n][m].weight);
}
printf(\"邻接矩阵为:\\n\");
for ( i = 1; i <= G->vexnum; i++)
{
for ( j = 1; j <= G->vexnum; j++)
{
printf(\"%d \",G->arc[i][j].adj);
}
printf(\"\\n\");
}
}
void sort(edge edges[],MGraph *G)//对权值进行排序
{
int i, j;
for ( i = 1; i < G->arcnum; i++)
{
for ( j = i + 1; j <= G->arcnum; j++)
{
if (edges[i].weight > edges[j].weight)
{
Swapn(edges, i, j);
}
}
}
printf(\"权排序之后的为:\\n\");
for (i = 1; i < G->arcnum; i++)
{
printf(\"<< %d, %d >> %d\\n\", edges[i].begin, edges[i].end, edges[i].weight);
}
}
void Swapn(edge *edges,int i, int j)//交换权值 以及头和尾
{
int temp;
temp = edges[i].begin;
edges[i].begin = edges[j].begin;
edges[j].begin = temp;
temp = edges[i].end;
edges[i].end = edges[j].end;
edges[j].end = temp;
temp = edges[i].weight;
edges[i].weight = edges[j].weight;
edges[j].weight = temp;
}
void MiniSpanTree(MGraph *G)//生成最小生成树
{
int i, j, n, m;
int k = 1;
int parent[M];
edge edges[M];
for ( i = 1; i < G->vexnum; i++)
{
for (j = i + 1; j <= G->vexnum; j++)
{
if (G->arc[i][j].adj == 1)
{
edges[k].begin = i;
edges[k].end = j;
edges[k].weight = G->arc[i][j].weight;
k++;
}
}
}
sort(edges, G);
for (i = 1; i <= G->arcnum; i++)
{
parent[i] = 0;
}
printf(\"最小生成树为:\\n\");
for (i = 1; i <= G->arcnum; i++)//核心部分
{
n = Find(parent, edges[i].begin);
m = Find(parent, edges[i].end);
if (n != m)
{
parent[n] = m;
printf(\"<< %d, %d >> %d\\n\", edges[i].begin, edges[i].end, edges[i].weight);
}
}
}
int Find(int *parent, int f)//找尾
{
while ( parent[f] > 0)
{
f = parent[f];
}
return f;
}