這是用Java寫的控制臺(tái)程序感昼,我建議各位看官先運(yùn)行再看代碼荷憋。
package com.company;
public class Main {
public static void main(String[] args) {
// write your code here
int[][] adjustMatrix = {
{0,7,-1,5,-1,-1,-1},
{-1,0,8,9,7,-1,-1},
{-1,-1,0,-1,5,-1,-1},
{-1,-1,-1,0,15,6,-1},
{-1,-1,-1,-1,0,8,9},
{-1,-1,-1,-1,-1,0,11},
{-1,-1,-1,-1,-1,-1,0}
};
Kruskal.kruskal0(adjustMatrix);
}
}
package com.company;
public class Kruskal {
/**
* 這是傳說中著名的克魯斯卡爾算法
* 用于生成最小生成樹
* 適用于無向連通圖
* 權(quán)值必須為自然數(shù)
* @param sourceArray
*/
static public void kruskal0(int[][] sourceArray) {
int arrayLength = sourceArray.length;
//第一步對輸入的
// 矩陣按照權(quán)值
// 進(jìn)行從小到大
// 排序因?yàn)殒湵? // 的插入時(shí)間復(fù)
// 雜度為O(1),
// 所以此處采用
// 單向鏈表來構(gòu)
// 造從小到大有
// 序的序列阅仔。
SingleLinkNode headPointer = new SingleLinkNode(-1,-1,-1);
for (int counter = 0;counter < arrayLength;counter++) {
for (int counter0 = counter + 1;counter0 < arrayLength;counter0++) {
if (sourceArray[counter][counter0] > 0) {
SingleLinkNode newNode = new SingleLinkNode(counter,counter0,sourceArray[counter][counter0]);
SingleLinkNode currentPointer = headPointer;
while (currentPointer.nextPointer != null &&
currentPointer.nextPointer.getWeight() < newNode.getWeight())
currentPointer = currentPointer.nextPointer;
newNode.nextPointer = currentPointer.nextPointer;
currentPointer.nextPointer = newNode;
}
}
}
//用來創(chuàng)建連通圖結(jié)點(diǎn)的集合吹散,每個(gè)二維
// 數(shù)組代表一個(gè)集合。初始情況下八酒,因?yàn)? // 每個(gè)頂點(diǎn)自成一個(gè)連通圖空民,所以默認(rèn)
// 值情況下每個(gè)二維數(shù)組的下標(biāo)為0的值
// 是該二維數(shù)組的index。因?yàn)槊總€(gè)二維
// 數(shù)組被當(dāng)成一個(gè)棧來使用羞迷,并且已經(jīng)有
// 了一個(gè)元素界轩,所以棧頂指針為0.此處為
// 判斷新邊加入到已有集合的時(shí)候是否已
// 經(jīng)形成了環(huán)。
//連通圖的各集合
int[][] circleUnion = new int[arrayLength][arrayLength];
for (int counter = 0;counter < arrayLength;counter++)
circleUnion[counter][0] = counter;
//這是棧頂指針衔瓮,初始狀態(tài)的時(shí)候每個(gè)棧中都有一個(gè)元素浊猾,所以棧頂指針置為0.
int[] unionTopPointer = new int[arrayLength];
for (int counter = 0;counter < arrayLength;counter++)
unionTopPointer[counter] = 0;
//此數(shù)組中代表的是每個(gè)頂點(diǎn)此時(shí)處于哪個(gè)集合之中。
int[] vertexMarkArray = new int[arrayLength];
//因?yàn)槟J(rèn)情況下每個(gè)頂點(diǎn)自成一個(gè)連通圖热鞍,
// 所以該頂點(diǎn)所屬的集合編號就是它自己的編號葫慎。
for (int counter = 0;counter < arrayLength;counter++)
vertexMarkArray[counter] = counter;
//逐個(gè)選擇最小的邊進(jìn)行判斷,合格的被加入到某集合中薇宠。不合格的從鏈表中摳去偷办。
SingleLinkNode currentPointer = headPointer;
//如果2個(gè)頂點(diǎn)對應(yīng)的編號相同代表
// 它們屬于同一個(gè)連通分量,換句
// 話說已經(jīng)在一個(gè)連通圖里面了澄港。
// 不同則可以合并椒涯,不過前提是這
// 兩個(gè)頂點(diǎn)所屬集合不為空。
while (currentPointer.nextPointer != null) {
System.out.println("打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.println(counter + "-->" + vertexMarkArray[counter]);
}
System.out.println("打印調(diào)整前各集合桶的狀態(tài)變化");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.print("桶" + counter + ":");
for (int counter0 = 0;counter0 <= unionTopPointer[counter];counter0++) {
System.out.print(circleUnion[counter][counter0] + " ");
}
System.out.println();
}
//鏈表中某結(jié)點(diǎn)的源頂點(diǎn)編號和目標(biāo)頂點(diǎn)編號
int sourceIndex = currentPointer.nextPointer.getSourceNode();
int targetIndex = currentPointer.nextPointer.getTargetNode();
System.out.println("新頂點(diǎn)對:(" + sourceIndex + "," + targetIndex + ")");
if (vertexMarkArray[sourceIndex] != vertexMarkArray[targetIndex]
&& unionTopPointer[vertexMarkArray[sourceIndex]] > -1
&& unionTopPointer[vertexMarkArray[targetIndex]] > -1) {
System.out.println("對應(yīng)的桶編號為:(" + vertexMarkArray[sourceIndex] + "," + vertexMarkArray[targetIndex] + ")");
//比較一個(gè)哪個(gè)集合元素多回梧,具體就是比較棧
// 頂指針废岂。因?yàn)橐焉俚臈V械脑剞D(zhuǎn)移到多的棧中祖搓。
if (unionTopPointer[vertexMarkArray[targetIndex]] > unionTopPointer[vertexMarkArray[sourceIndex]]) {
int tempIndex = sourceIndex;
sourceIndex = targetIndex;
targetIndex = tempIndex;
}
int moreBucket = vertexMarkArray[sourceIndex];
int lessBucket = vertexMarkArray[targetIndex];
while (unionTopPointer[lessBucket] > -1) {
int vertexId = circleUnion[lessBucket][unionTopPointer[lessBucket]--];
circleUnion[moreBucket][++unionTopPointer[moreBucket]] = vertexId;
//在轉(zhuǎn)移的同時(shí)刷新被移動(dòng)的每個(gè)頂點(diǎn)所屬的集合編號。
vertexMarkArray[vertexId] = moreBucket;
}
//只要棧中的元素個(gè)數(shù)達(dá)到了頂點(diǎn)的總數(shù)就代表算法完成了湖苞。
if (unionTopPointer[vertexMarkArray[sourceIndex]] == arrayLength - 1) {
currentPointer.nextPointer.nextPointer = null;
System.out.println("打印調(diào)整后各集合桶的狀態(tài)變化");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.print("桶" + counter + ":");
for (int counter0 = 0;counter0 <= unionTopPointer[counter];counter0++) {
System.out.print(circleUnion[counter][counter0] + " ");
}
System.out.println();
}
System.out.println("集合歸并結(jié)束");
break;
}
currentPointer = currentPointer.nextPointer;
} else {
System.out.println("舍去");
currentPointer.nextPointer = currentPointer.nextPointer.nextPointer;
}
System.out.println("打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.println(counter + "-->" + vertexMarkArray[counter]);
}
//打印各集合桶的狀態(tài)變化
System.out.println("打印調(diào)整后各集合桶的狀態(tài)變化");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.print("桶" + counter + ":");
for (int counter0 = 0;counter0 <= unionTopPointer[counter];counter0++) {
System.out.print(circleUnion[counter][counter0] + " ");
}
System.out.println();
}
System.out.println();
}
//打印剩下的摳去不合格結(jié)點(diǎn)后的鏈表
System.out.println("\n結(jié)果集為:");
while (headPointer.nextPointer != null) {
System.out.println("(" + headPointer.nextPointer.getSourceNode() + "," + headPointer.nextPointer.getTargetNode() + ")-->" + headPointer.nextPointer.getWeight());
headPointer = headPointer.nextPointer;
}
}
/**
* 本實(shí)現(xiàn)是對kruskal0的改進(jìn)
* @param sourceArray
*/
static public void kruskal1(int[][] sourceArray) {
int arrayLength = sourceArray.length;
SingleLinkNode headPointer = new SingleLinkNode(-1,-1,-1);
for (int counter = 0;counter < arrayLength;counter++) {
for (int counter0 = counter + 1;counter0 < arrayLength;counter0++) {
if (sourceArray[counter][counter0] > 0) {
SingleLinkNode newNode = new SingleLinkNode(counter,counter0,sourceArray[counter][counter0]);
SingleLinkNode currentPointer = headPointer;
while (currentPointer.nextPointer != null &&
currentPointer.nextPointer.getWeight() < newNode.getWeight())
currentPointer = currentPointer.nextPointer;
newNode.nextPointer = currentPointer.nextPointer;
currentPointer.nextPointer = newNode;
}
}
}
//此處原本采用了n×n的二維數(shù)組拯欧,
// 但是實(shí)際元素?cái)?shù)量只有n,所以
// 利用率只有1/n袒啼,太低了哈扮,于是
// 考慮用鏈表來實(shí)現(xiàn)。而且這樣做
// 也不用再使用棧頂指針了蚓再。
DoubleLinkNode[] circleUnion = new DoubleLinkNode[arrayLength];
//在這里姑且用結(jié)點(diǎn)的vertexId屬性
// 來標(biāo)識連通集的ID吧滑肉,用counter屬性來記錄當(dāng)前桶的頂點(diǎn)個(gè)數(shù)。
for (int counter = 0;counter < arrayLength;counter++)
circleUnion[counter] = new DoubleLinkNode(1,counter);
int[] vertexMarkArray = new int[arrayLength];
for (int counter = 0;counter < arrayLength;counter++)
vertexMarkArray[counter] = counter;
SingleLinkNode currentPointer = headPointer;
while (currentPointer.nextPointer != null) {
System.out.println("打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.println(counter + "-->" + vertexMarkArray[counter]);
}
System.out.println("打印調(diào)整前各集合桶的狀態(tài)變化");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.print("桶" + counter + ":");
DoubleLinkNode bucketHeadPointer = circleUnion[counter];
while (bucketHeadPointer != null) {
System.out.print(bucketHeadPointer.getVertexId() + " ");
bucketHeadPointer = bucketHeadPointer.prePointer;
}
System.out.println();
}
int sourceIndex = currentPointer.nextPointer.getSourceNode();
int targetIndex = currentPointer.nextPointer.getTargetNode();
System.out.println("新頂點(diǎn)對:(" + sourceIndex + "," + targetIndex + ")");
if (vertexMarkArray[sourceIndex] != vertexMarkArray[targetIndex]
&& circleUnion[vertexMarkArray[sourceIndex]] != null
&& circleUnion[vertexMarkArray[targetIndex]] != null) {
System.out.println("對應(yīng)的桶編號為:(" + vertexMarkArray[sourceIndex] + "," + vertexMarkArray[targetIndex] + ")");
if (circleUnion[vertexMarkArray[targetIndex]].getCounter() >
circleUnion[vertexMarkArray[sourceIndex]].getCounter()) {
int tempIndex = sourceIndex;
sourceIndex = targetIndex;
targetIndex = tempIndex;
}
int moreBucket = vertexMarkArray[sourceIndex];
int lessBucket = vertexMarkArray[targetIndex];
while (circleUnion[lessBucket] != null) {
DoubleLinkNode moreHeadPointer = circleUnion[moreBucket];
DoubleLinkNode lessHeadPointer = circleUnion[lessBucket];
DoubleLinkNode movedPointer = lessHeadPointer;
lessHeadPointer = lessHeadPointer.prePointer;
movedPointer.nextPointer = null;
movedPointer.prePointer = null;
vertexMarkArray[movedPointer.getVertexId()] = moreBucket;
moreHeadPointer.nextPointer = movedPointer;
movedPointer.prePointer = moreHeadPointer;
movedPointer.setCounter(moreHeadPointer.getCounter() + 1);
moreHeadPointer = movedPointer;
circleUnion[moreBucket] = moreHeadPointer;
circleUnion[lessBucket] = lessHeadPointer;
}
if (circleUnion[moreBucket].getCounter() == arrayLength) {
currentPointer.nextPointer.nextPointer = null;
System.out.println("打印調(diào)整后各集合桶的狀態(tài)變化");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.print("桶" + counter + ":");
DoubleLinkNode bucketHeadPointer = circleUnion[counter];
while (bucketHeadPointer != null) {
System.out.print(bucketHeadPointer.getVertexId() + " ");
bucketHeadPointer = bucketHeadPointer.prePointer;
}
System.out.println();
}
System.out.println("集合歸并結(jié)束");
break;
}
currentPointer = currentPointer.nextPointer;
} else {
System.out.println("舍去");
currentPointer.nextPointer = currentPointer.nextPointer.nextPointer;
}
System.out.println("打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.println(counter + "-->" + vertexMarkArray[counter]);
}
System.out.println("打印調(diào)整后各集合桶的狀態(tài)變化");
for (int counter = 0;counter < arrayLength;counter++) {
System.out.print("桶" + counter + ":");
DoubleLinkNode bucketHeadPointer = circleUnion[counter];
while (bucketHeadPointer != null) {
System.out.print(bucketHeadPointer.getVertexId() + " ");
bucketHeadPointer = bucketHeadPointer.prePointer;
}
System.out.println();
}
System.out.println();
}
System.out.println("\n結(jié)果集為:");
while (headPointer.nextPointer != null) {
System.out.println("(" + headPointer.nextPointer.getSourceNode() + "," + headPointer.nextPointer.getTargetNode() + ")-->" + headPointer.nextPointer.getWeight());
headPointer = headPointer.nextPointer;
}
}
}
package com.company;
public class SingleLinkNode {
private int sourceNode;
private int targetNode;
private int weight;
public SingleLinkNode nextPointer = null;
public SingleLinkNode(int sourceNode, int targetNode, int weight) {
this.sourceNode = sourceNode;
this.targetNode = targetNode;
this.weight = weight;
}
public int getWeight() {
return weight;
}
public int getSourceNode() {
return sourceNode;
}
public int getTargetNode() {
return targetNode;
}
}
package com.company;
public class DoubleLinkNode {
private int counter;
private int vertexId;
public DoubleLinkNode prePointer = null;
public DoubleLinkNode nextPointer = null;
public DoubleLinkNode(int counter, int vertexId) {
this.counter = counter;
this.vertexId = vertexId;
}
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
public int getVertexId() {
return vertexId;
}
}
輸出如下
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->1
2-->2
3-->3
4-->4
5-->5
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0
桶1:1
桶2:2
桶3:3
桶4:4
桶5:5
桶6:6
新頂點(diǎn)對:(2,4)
對應(yīng)的桶編號為:(2,4)
打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->1
2-->2
3-->3
4-->2
5-->5
6-->6
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0
桶1:1
桶2:2 4
桶3:3
桶4:
桶5:5
桶6:6
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->1
2-->2
3-->3
4-->2
5-->5
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0
桶1:1
桶2:2 4
桶3:3
桶4:
桶5:5
桶6:6
新頂點(diǎn)對:(0,3)
對應(yīng)的桶編號為:(0,3)
打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->1
2-->2
3-->0
4-->2
5-->5
6-->6
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0 3
桶1:1
桶2:2 4
桶3:
桶4:
桶5:5
桶6:6
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->1
2-->2
3-->0
4-->2
5-->5
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0 3
桶1:1
桶2:2 4
桶3:
桶4:
桶5:5
桶6:6
新頂點(diǎn)對:(3,5)
對應(yīng)的桶編號為:(0,5)
打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->1
2-->2
3-->0
4-->2
5-->0
6-->6
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0 3 5
桶1:1
桶2:2 4
桶3:
桶4:
桶5:
桶6:6
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->1
2-->2
3-->0
4-->2
5-->0
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0 3 5
桶1:1
桶2:2 4
桶3:
桶4:
桶5:
桶6:6
新頂點(diǎn)對:(1,4)
對應(yīng)的桶編號為:(1,2)
打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->2
2-->2
3-->0
4-->2
5-->0
6-->6
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0 3 5
桶1:
桶2:2 4 1
桶3:
桶4:
桶5:
桶6:6
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->2
2-->2
3-->0
4-->2
5-->0
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0 3 5
桶1:
桶2:2 4 1
桶3:
桶4:
桶5:
桶6:6
新頂點(diǎn)對:(0,1)
對應(yīng)的桶編號為:(0,2)
打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->0
2-->0
3-->0
4-->0
5-->0
6-->6
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0 3 5 1 4 2
桶1:
桶2:
桶3:
桶4:
桶5:
桶6:6
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->0
2-->0
3-->0
4-->0
5-->0
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0 3 5 1 4 2
桶1:
桶2:
桶3:
桶4:
桶5:
桶6:6
新頂點(diǎn)對:(4,5)
舍去
打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->0
2-->0
3-->0
4-->0
5-->0
6-->6
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0 3 5 1 4 2
桶1:
桶2:
桶3:
桶4:
桶5:
桶6:6
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->0
2-->0
3-->0
4-->0
5-->0
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0 3 5 1 4 2
桶1:
桶2:
桶3:
桶4:
桶5:
桶6:6
新頂點(diǎn)對:(1,2)
舍去
打印調(diào)整后的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->0
2-->0
3-->0
4-->0
5-->0
6-->6
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0 3 5 1 4 2
桶1:
桶2:
桶3:
桶4:
桶5:
桶6:6
打印調(diào)整前的各結(jié)點(diǎn)的集合歸屬狀態(tài)
0-->0
1-->0
2-->0
3-->0
4-->0
5-->0
6-->6
打印調(diào)整前各集合桶的狀態(tài)變化
桶0:0 3 5 1 4 2
桶1:
桶2:
桶3:
桶4:
桶5:
桶6:6
新頂點(diǎn)對:(4,6)
對應(yīng)的桶編號為:(0,6)
打印調(diào)整后各集合桶的狀態(tài)變化
桶0:0 3 5 1 4 2 6
桶1:
桶2:
桶3:
桶4:
桶5:
桶6:
集合歸并結(jié)束
結(jié)果集為:
(2,4)-->5
(0,3)-->5
(3,5)-->6
(1,4)-->7
(0,1)-->7
(4,6)-->9