最小生成树 给定一个带权的无向连通图 选取边将所有顶点连起来的同时 边的和的权值最小 即为最小生成树
prim算法
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PrimTest {
public static void main(String[] args) {
//普利姆算法 求图的最小生成树 普利姆算法生成的边的数量为 节点数量-1
pmap map = new pmap(7);
char []node = {'A','B','C','D','E','F','G'};
int [][]nodeMap = {
{0,5,7,0,0,0,2},
{5,0,0,9,0,0,3},
{7,0,0,0,8,0,0},
{0,9,0,0,0,4,0},
{0,0,8,0,0,5,4},
{0,0,0,4,5,0,6},
{2,3,0,0,4,6,0},
};
map.fastSetMap(node,nodeMap);
//显示图
map.showMap();
System.out.println("普利姆算法");
int count = map.prim(map);
System.out.println("总距离"+count);
}
}
//图
class pmap{
int nodeOrder;//节点的数量
char []node;//节点
int [][]nodeMap;//图的邻接矩阵
public pmap(int nodeOrder){
this.nodeOrder = nodeOrder;
node = new char[nodeOrder];
nodeMap = new int[nodeOrder][nodeOrder];
}
//因为只是为了测试生成 最小生成树 所以就快捷的创建一个图
public void fastSetMap(char []node,int [][]nodeMap){
this.node = node;
this.nodeMap = nodeMap;
}
//显示图的邻接矩阵
public void showMap(){
for (int []i:nodeMap){
System.out.println(Arrays.toString(i));
}
}
//接收一个图 然后生成他的最小生成树
public int prim(pmap map){
//总距离
int count = 0;
//这是还没有加入到最小生成树内的 节点
ArrayList<Integer> notDone = new ArrayList<Integer>();
//当前还没有开始生成 所以把所有节点(的索引)都加入到 没有访问(加入最小生成树) 的集合中
for (int i=0;i<map.node.length;i++){
notDone.add(i);
}
//这是已经加入到最小生成树内的 节点 默认为空
ArrayList<Integer> haveDone = new ArrayList<Integer>();
//从未访问的集合中 取出一位 加入已访问的集合中 意思是从这一位开始生成 无论从哪一个生成 只会影响顺序 不会影响总距离
haveDone.add(notDone.remove(0));
//循环节点数-1次 因为边最多这么多条
for (int j=1;j<map.node.length;j++){
int min = 100;//应该根据邻接矩阵中的最大值来赋值 不会出错 为了方便暂时用100来测试
int b1 = -1;
int b2 = -1;
int sign = -1;
for (int k=0;k<haveDone.size();k++){
for (int q=0;q<notDone.size();q++){
int value = map.nodeMap[haveDone.get(k)][notDone.get(q)];
if (value>0&&value<min){
min = value;
b1 = haveDone.get(k);
b2 = notDone.get(q);
sign = q;
}
}
}
if (b1!=-1&&b2!=-1){
haveDone.add(notDone.remove(sign));
count += map.nodeMap[b1][b2];
System.out.println("本轮连接点:"+map.node[b1]+"->:"+map.node[b2]+"距离"+map.nodeMap[b1][b2]);
}
}
return count;
}
}
kruskal算法
package KruskalTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class KruskalTest {
public static void main(String[] args) {
pmap map = new pmap(7);
char []node = {'A','B','C','D','E','F','G'};
int [][]nodeMap = {
{0, 12, 0, 0, 0, 16, 14},
{12, 0, 10, 0, 0, 7, 0},
{0, 10, 0, 3, 5, 6, 0},
{0, 0, 3, 0, 4, 0, 0},
{0, 0, 5, 4, 0, 2, 8},
{16, 7, 6, 0, 2, 0, 9},
{14, 0, 0, 0, 8, 9, 0},
};
map.fastSetMap(node,nodeMap);
System.out.println("图的邻接矩阵");
map.showMap();
System.out.println("该图的最少生成树(克鲁斯卡尔算法)");
map.kruskal();
}
}
//图
class pmap{
int chang;
int nodeOrder;//节点的数量
char []node;//节点
int [][]nodeMap;//图的邻接矩阵
public pmap(int nodeOrder){
this.nodeOrder = nodeOrder;
node = new char[nodeOrder];
nodeMap = new int[nodeOrder][nodeOrder];
}
//因为只是为了测试生成 最小生成树 所以就快捷的创建一个图
public void fastSetMap(char []node,int [][]nodeMap){
this.node = node;
this.nodeMap = nodeMap;
for (int i=0;i<node.length;i++){
for (int j = i+1; j < node.length; j++) {
if (nodeMap[i][j]!=0){
chang++;
}
}
}
// System.out.println(chang);
}
//显示图的邻接矩阵
public void showMap(){
for (int []i:nodeMap){
System.out.println(Arrays.toString(i));
}
}
//kruskal算法生成最小生成树 边的数量仍是顶点数量-1
//获取边的总数量 排序 依次加入 结果树中 每次加入判断当前加入的边的 两端顶点的 当前终点 是否相同 相同的话会形成回路 所以只有不同的时候才加入结果树
//kruskal算法
public void kruskal(){
//用来储存节点的终点 长度为节点数
int []ends = new int[this.node.length];
//最后生成最小生成树的边
int index = 0;
bian []k = new bian[this.node.length-1];
// ArrayList<Integer> huan = new ArrayList<Integer>();
//获取排序后的所有边
ArrayList<bian> allBian = getAllBian();
// System.out.println(allBian.size());
for (int i=0;i<chang;i++){
//获取当前边的起点的索引
int start = getNodeSign(allBian.get(i).start);
int end = getNodeSign(allBian.get(i).end);
//获取上方两点的当前终点 并判断是否想等 如果不相等 继续运行
// System.out.println("点"+start+"的终点为"+getNodeEnd(ends,start)+" "+"点"+end+"的终点为"+getNodeEnd(ends,end));
if (getNodeEnd(ends,start) != getNodeEnd(ends,end)){//!huan.contains(start)||!huan.contains(end)
System.out.println("点"+start+"."+allBian.get(i).start+"的终点为"+getNodeEnd(ends,start)+" "+"点"+end+"."+allBian.get(i).end+"的终点为"+getNodeEnd(ends,end));
//标记新的终点 !!!!一定注意 这里设置的是当前边的起点(边a连b中的a)的终点 的终点 为 当前边的终点(边a连b中的b)的终点
ends[getNodeEnd(ends,start)] = getNodeEnd(ends,end);
// huan.add(start);
// huan.add(end);
// System.out.println(1);
//将当前符合要求的边加入 结果中
k[index] = allBian.get(i);
index++;
}
}
//遍历生成的最小生成树 验证..
for (bian v:k){
System.out.print(v+" ");
}
}
//传入节点名称 获取节点索引
public int getNodeSign(char a){
for (int i=0;i<this.node.length;i++){
if (a == this.node[i]){
return i;
}
}
return -1;
}
//获取当前图的所有边 返回 这些边构成的集合
public ArrayList<bian> getAllBian(){
//遍历邻接矩阵 在遍历列的时候 是从当前行数+1列开始的 这样可以避免 1-2 2-1 这种情况 和2-2的情况
ArrayList<bian> allBian= new ArrayList<bian>();
for (int i=0;i<this.node.length;i++){
for (int j=i+1;j<this.node.length;j++){
if (this.nodeMap[i][j]!=0){
//将有链接的边加入 allbian这个集合中
allBian.add(new bian(this.node[i],this.node[j],this.nodeMap[i][j]));
}
}
}
//对边进行排序(根据边的权值)
Collections.sort(allBian);
//返回排序完成的边
return allBian;
}
//查询当前顶点的终点
public int getNodeEnd(int []end,int i){
while (end[i]!=0){
i = end[i];
}
return i;
}
}
//定义一个边类 方便记录
class bian implements Comparable<bian>{
char start;//当前边的起点
char end;//当前边要连接的点(终点)
int value;//当前边的权值
public bian(char start,char end,int value){
this.start = start;
this.end = end;
this.value = value;
}
@Override
public int compareTo(bian o) {
return this.value - o.value;
}
@Override
public String toString() {
return start+"-"+value+"->"+end;
}
}