package Prim;
import com.sun.corba.se.impl.orbutil.graph.Graph;
import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
public class Prim {
public static void main(String[] args){
int[][] graph=new int[][]{{0,6,1,5,65535,65535},
{6,0,5,65535,3,65535},
{1,5,0,5,6,4},
{5,0,5,0,65535,2},
{65535,3,6,65535,0,6},
{65535,65535,4,2,6,0}};
MinTree minTree=new MinTree();
minTree.createMinTree(graph);
}
}
class MinTree{
public void createMinTree(int[][] graph) {
int i, j,k=0 ,m;
int[] lowcost = new int[6];//建立一个存储已被包入当前生成树的所有可达路径的权值
int[] adjvex = new int[6];//用来记录可达路径权值的起始点,用于输出路径
//接下来初始化第一个点
lowcost[0] = 0;//我们要将所有访问过的节点包括设为0,以至于不会被访问到
adjvex[0] = 0;//我们设置第一个顶点为0节点
//将第一行的数据存入lowcost中
for (i = 0; i < 6; i++) {
lowcost[i] = graph[0][i];//初始化到所有点的权值,访问不到的是65535,以后会有新的点来更新这个数据
adjvex[i] = 0;//先设置所有点都是从vo发出的
}
/**
* 先选出当前可达点的权值最小的点,并加入生成树
* **/
for (i = 1; i < 6; i++) {//需要连接几个点就遍历几次
int min = 65535;//定义在这里防止min拿到了最小值,之后min无法改变
for (j = 1; j < 6; j++) {//遍历所有lowcost找到现在最小的权值
if (lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];//将最小权值点赋给lowcost,循环结束得到最小的
k=j;//将最小权值点的下标值存入k
}
}
System.out.println(adjvex[k]+"-"+k);
lowcost[k]=0;//将这个点包入生成树
/**
* 下面的步骤:
* 作用:因为加入了新的节点,所以更新到各个点的最小权值
**/
for (m=1;m<6;m++){//将新加入生成树的点的连接点的权值全部更新至lowcost
if(graph[k][m]!=0&&graph[k][m]
int i, j,k=0 ,m;
int[] lowcost = new int[6];//建立一个存储已被包入当前生成树的所有可达路径的权值
int[] adjvex = new int[6];//用来记录可达路径权值的起始点,用于输出路径
//接下来初始化第一个点
lowcost[0] = 0;//我们要将所有访问过的节点包括设为0,以至于不会被访问到
adjvex[0] = 0;//我们设置第一个顶点为0节点
//将第一行的数据存入lowcost中
for (i = 0; i < 6; i++) {
lowcost[i] = graph[0][i];//初始化到所有点的权值,访问不到的是65535,以后会有新的点来更新这个数据
adjvex[i] = 0;//先设置所有点都是从vo发出的
}
/**
* 先选出当前可达点的权值最小的点,并加入生成树
* **/
for (i = 1; i < 6; i++) {//需要连接几个点就遍历几次
int min = 65535;//定义在这里防止min拿到了最小值,之后min无法改变
for (j = 1; j < 6; j++) {//遍历所有lowcost找到现在最小的权值
if (lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];//将最小权值点赋给lowcost,循环结束得到最小的
k=j;//将最小权值点的下标值存入k
}
}
System.out.println(adjvex[k]+"-"+k);//输出边
lowcost[k]=0;//将这个点包入生成树
* 下面的步骤:
* 作用:因为加入了新的节点,所以更新到各个点的最小权值
**/
for (m=1;m<6;m++){//将新加入生成树的点的连接点的权值全部更新至lowcost
if(graph[k][m]!=0&&graph[k][m] * 下面的步骤:
* 作用:因为加入了新的节点,所以更新到各个点的最小权值
**/
for (m=1;m<6;m++){//将新加入生成树的点的连接点的权值全部更新至lowcost
if(graph[k][m]!=0&&graph[k][m]
当更新后,到某个点最小权值就是由这个当前操作点发出的。那么我们把这个点的下标赋值给k,m是当前操作点能到达且是当前生成树中最近到达的点的下标。这样存储当我们需要时就能直接通过adjvex[某点]得出他是哪个点发出的。如:
adjvex={0,5} 那么下标v1这个点就是由v5发出的。
克鲁斯卡尔(Kruskal算法)
算法思想:通过按顺序从小到大寻找最短边,每次要进行判断是否会形成环,直接最后结束,变成生成最小生成树。
算法实现:
package kruskal;
/*
* 算法思路:通过边为目标构建最小生成树
* 算法过程:建立一个边集数组由小到大的存储边的两个顶点和权值,通过顺序遍历能按大小找到所有边,并进行输出
* 算法问题:当生成多个边时可能会造成环
* 解决思路:我们通过一个数组,在起点下标处存他的终点下标,这样就相当于有了顺序,当某个起点到达它相连的最后一个点时,这
* 个点和终点所到达的点是同一个点,那么这条边会构成环相同。
*
*/
public class KruskalMain {
public static void main(String[] args){
//建立一个边集数组,按权值顺序存储
Edge[] edge=new Edge[15];
for(int i=0;i<15;i++)
edge[i] =new Edge();
edge[0].begin=4;
edge[0].end=7;
edge[0].weight=7;
edge[1].begin=2;
edge[1].end=8;
edge[1].weight=8;
edge[2].begin=0;
edge[2].end=1;
edge[2].weight=10;
edge[3].begin=0;
edge[3].end=5;
edge[3].weight=11;
edge[4].begin=1;
edge[4].end=8;
edge[4].weight=12;
edge[5].begin=3;
edge[5].end=7;
edge[5].weight=16;
edge[6].begin=1;
edge[6].end=6;
edge[6].weight=16;
edge[7].begin=5;
edge[7].end=6;
edge[7].weight=17;
edge[8].begin=1;
edge[8].end=2;
edge[8].weight=18;
edge[9].begin=6;
edge[9].end=7;
edge[9].weight=19;
edge[10].begin=3;
edge[10].end=4;
edge[10].weight=20;
edge[11].begin=3;
edge[11].end=8;
edge[11].weight=21;
edge[12].begin=2;
edge[12].end=3;
edge[12].weight=22;
edge[13].begin=3;
edge[13].end=6;
edge[13].weight=24;
edge[14].begin=4;
edge[14].end=5;
edge[14].weight=26;
Kruskal kruskal=new Kruskal();
kruskal.kruskalMethod(edge);
}
}
//边集数组类
class Edge
{
int begin;
int end;
int weight;
}
class Kruskal{
public void kruskalMethod(Edge[] edge){
int i,j;
int m,n;//m存放起点开始下标最后一个点,n存终点开始下标最后一个点。
int[] parent =new int[15]; //建立一个数组,专门存储下一个点的下标,用来判断是否形成回路
for(i=0;i<15;i++) //将parent中所有下标赋值为0,这样表示他们一开始都还没有相连的点
parent[i]=0;
for(i=0;i<15;i++) {//遍历每条边,将他们放入生成树
/*
* 判断是否形成环
*/
//1.得到这个点的最后一个无相连的点
m=find(parent,edge[i].begin);
n=find(parent,edge[i].end);
//2.判断起点的最后一个点和终点的最后一个点是否相同,相同则为环,不相同把n放入m的下标,打印这条边
if(m!=n){
parent[m]=n;
System.out.println(edge[i].begin+"-"+edge[i].end+"="+edge[i].weight);//输出起点和终点的边
}
}
}
public int find(int[] parent,int f){//判断下一个点是否有连接,有则换到那个点,没有返回这个点
while (parent[f]>0){
f=parent[f];
}
return f;
}
}
* 算法思路:通过边为目标构建最小生成树 *
算法过程:建立一个边集数组由小到大的存储边的两个顶点和权值,通过顺序遍历能按大小找到所有边,并进行输出 * 算法问题:当生成多个边时可能会造成环 *
解决思路:我们通过一个数组,在起点下标处存他的终点下标,这样就相当于有了顺序,当某个起点到达它相连的最后一个点时,这 * 个点和终点所到达的点是同一个点,那么这条边会构成环相同。 * 其实把这个生成树连起来的过程像是连一个有向图的过程,因为每次都要看这个点是否有下一个连接点 *
*/
这个算法在我的理解中分为三步
第一步:初始化
int i,j;
int m,n;//m存放起点开始下标最后一个点,n存终点开始下标最后一个点。
int[] parent =new int[15]; //建立一个数组,专门存储下一个点的下标,用来判断是否形成回路
for(i=0;i<15;i++) //将parent中所有下标赋值为0,这样表示他们一开始都还没有相连的点
parent[i]=0;
int i,j;
int m,n;//m存放起点开始下标最后一个点,n存终点开始下标最后一个点。
int[] parent =new int[15]; //建立一个数组,专门存储下一个点的下标,用来判断是否形成回路
for(i=0;i<15;i++) //将parent中所有下标赋值为0,这样表示他们一开始都还没有相连的点
parent[i]=0;
parent这个数组的作用是判断某个点是否还有相连的下一个点,没有的话则为0,有的话存储那个点的下标,这样做是为了判断是否生成环。
第二步:判断是否成环
for(i=0;i<15;i++) {//遍历每条边,将他们放入生成树
/*
* 判断是否形成环
*/
//1.得到这个点的最后一个无相连的点
m=find(parent,edge[i].begin);
n=find(parent,edge[i].end);
for(i=0;i<15;i++) {//遍历每条边,将他们放入生成树
/*
* 判断是否形成环
*/
//1.得到这个点的最后一个无相连的点
m=find(parent,edge[i].begin);
n=find(parent,edge[i].end);
find函数
public int find(int[] parent,int f){//判断下一个点是否有连接,有则换到那个点,没有返回这个点
while (parent[f]>0){
f=parent[f];
}
return f;
成环的条件:
我们通过一个数组,在起点下标处存他的终点下标,这样就相当于有了顺序,当某个起点到达它相连的最后一个点时,这
* 个点和终点所到达的点是同一个点,那么这条边会构成环相同。
这一部分就是围绕这个条件设计的
第三部分:判断是否成环,不成环输出:
//2.判断起点的最后一个点和终点的最后一个点是否相同,相同则为环,不相同把n放入m的下标,打印这条边
if(m!=n){
parent[m]=n;
System.out.println(edge[i].begin+"-"+edge[i].end+"="+edge[i].weight);//输出起点和终点的边
}
}
克鲁斯尔卡算法是针对边来展开的。边数少会效率很高,所以对于稀疏图更好,相反的普里姆算法在处理稠密图的能力高于克鲁斯尔卡算法。