//带权的无向邻接矩阵
public class Graph {
ArrayList<String> vertexList;
int[][] edgeMatrix;
int numOfVertex;
int numOfEdge;
int size;
public Graph() {
}
public Graph(int size) {
vertexList = new ArrayList<String>(size);
edgeMatrix = new int[size][size];
//初始化邻接矩阵
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
if (x != y) {
edgeMatrix[x][y] = 0x3f;
}
}
}
numOfEdge = 0;
numOfVertex = 0;
this.size = size;
}
public void addVertex(String v) {
vertexList.add(v);
numOfVertex++;
}
public void addEge(int from, int to, int weight) {
edgeMatrix[from][to] = weight;
edgeMatrix[to][from] = weight;
numOfEdge++;
}
public void showGraph() {
for (int[] edges : edgeMatrix) {
for (int i : edges) {
System.out.print(i + "\t");
}
System.out.println();
}
}
public void prim() {
ArrayList<Integer> treeVertex = new ArrayList<>();//保存已经进入树的顶点的下标
treeVertex.add(0);//把0这个顶点加入到树顶点的集合中
while (true) {
if (treeVertex.size() == vertexList.size()) {
break;//树中已经包含了全部顶点,则退出循环
}
//遍历树顶点集合中的所有顶点,找到没有被访问过且权值最小的顶点
int temp;//暂时保留当前顶点的下标
int i = -1;//找到后,当前顶点的下标
int j = -1;//找到后,当前顶点的最小权值对应的顶点的下标
int min = 0x3f;//保存最小的权值,初始化为一个较大值
for (int x = 0; x < treeVertex.size(); x++) {
temp = treeVertex.get(x);//拿到树顶点集合中的顶点下标
//遍历这个顶点的邻接顶点
for (int y = 0; y < numOfVertex; y++) {
if (edgeMatrix[temp][y] != 0 && min > edgeMatrix[temp][y] && !treeVertex.contains(y)) {
min = edgeMatrix[temp][y];
i = temp;
j = y;
}
}
}
if (min != 0x3f) {//如果找到了,k指向顶点i的邻接顶点中,权值最小顶点的下标
treeVertex.add(j);
System.out.println(i + "---" + j + "---" + edgeMatrix[i][j]);
}
}
}
//得到按权值排好序的边集数组
public int[][] getEdgeArray() {
int[][] edgeArray = new int[numOfEdge][3];
int count = 0;
for (int x = 0; x < numOfVertex; x++) {
for (int y = x + 1; y < numOfVertex; y++) {
if (edgeMatrix[x][y] != 0 && edgeMatrix[x][y] != 0x3f) {
edgeArray[count][0] = x;
edgeArray[count][1] = y;
edgeArray[count][2] = edgeMatrix[x][y];
count++;
}
}
}
//边集数组按照权值从小到大排序(冒泡)
for (int y = 0; y < numOfEdge - 1; y++) {//大循环
for (int x = numOfEdge - 1; x > y; x--) {//小循环,从最后一个开始
if (edgeArray[x][2] < edgeArray[x - 1][2]) {
//交换数据
for (int i = 0; i < 3; i++) {
int temp = edgeArray[x - 1][i];
edgeArray[x - 1][i] = edgeArray[x][i];
edgeArray[x][i] = temp;
}
}
}
}
return edgeArray;
}
public void kruskal() {
int[][] edgeArray = getEdgeArray();//得到边集数组
int[] parent = new int[numOfVertex];//判断是否形成环路的数组,表示顶点i和顶点parent[i]在同一个连通分量中
for (int x = 0; x < numOfEdge; x++) {//循环遍历每一条边
int n = find(parent, edgeArray[x][0]);//该边的第一个顶点所在的连通分量的终点
int m = find(parent, edgeArray[x][1]);//该边的第二个顶点所在的连通分量的终点
if (n != m) {//这两个顶点的终点不一样,表示这两个顶点在不同的连通分量中
parent[n] = m;//加上这条边之后,这两个顶点所在的连通分量就会接通
System.out.println(edgeArray[x][0] + "---" + edgeArray[x][1] + "---" + edgeArray[x][2]);
}
}
}
//得到以i为起点的连通分量的终点(若形成回路,或只有一个顶点,终点为i本身)
public int find(int[] parent, int i) {
while (parent[i] != 0) {
i = parent[i];
}
return i;
}
public void printArray(int[][] edgeArray) {
for (int[] edges : edgeArray) {
for (int i : edges) {
System.out.print(i + "\t");
}
System.out.println();
}
}
}
public class GraphDemo {
public static void main(String[] args) {
Graph graph = new Graph(9);
//添加顶点
graph.addVertex("v0");
graph.addVertex("v1");
graph.addVertex("v2");
graph.addVertex("v3");
graph.addVertex("v4");
graph.addVertex("v5");
graph.addVertex("v6");
graph.addVertex("v7");
graph.addVertex("v8");
//添加边
graph.addEge(0, 1, 10);
graph.addEge(0, 5, 11);
graph.addEge(1, 6, 16);
graph.addEge(5, 6, 17);
graph.addEge(1, 8, 12);
graph.addEge(1, 2, 18);
graph.addEge(2, 8, 8);
graph.addEge(2, 3, 22);
graph.addEge(3, 8, 21);
graph.addEge(3, 6, 24);
graph.addEge(6, 7, 19);
graph.addEge(3, 7, 16);
graph.addEge(3, 4, 20);
graph.addEge(4, 5, 26);
graph.addEge(4, 7, 7);
graph.showGraph();//邻接矩阵
graph.prim();//普利姆算法
graph.printArray(graph.getEdgeArray());//边集数组
graph.kruskal();//克鲁斯卡尔算法
}
}