最小生成樹演算法之Kruskal演算法
阿新 • • 發佈:2018-12-17
最近做大題目主要運用的都是資料結構方面的題,既有之前的最短路徑的相關的演算法,也有現在的最小生成樹,這裡先講解Kruskal演算法,主要是我先在剛會這個,prim演算法,明天再看。 Kruskal演算法演算法其實和之前的djs演算法有點類似,主要還是每次迴圈找出區域性最優解,也就是最小權重的那條路,一次尋找即可,這裡作者一開始俊德實現起來並不麻煩,但之後發現,迴圈找出最優解不是最麻煩的,大不了每次排序,就行了,但是之後發現最難的一塊是不能出現環,舉個例子, 如果只是單純的按照權重來選擇,肯定是這樣選擇的1—>2,1—>4,2—>4,這樣的話會出現兩個問題,第一個就是出現了環即1—>2—>4—>1這樣顯然是不行的,第二問題就是,這樣選擇出來的點事不全的,缺少了3這個點,所以選擇路徑的時候不僅是要看權重,還應該看選擇的路徑是否會構成環這種不允許出現的情況,其實重點就是這裡,為了防止出現這種情況,我們又需要了解並查集這個概念,就是簡單的如果兩個數是一類的,那麼我們就將它們合併,否則就不動,這就是並的操作,之後就是查,通過不斷的向前查詢,直到查詢到該節點的根節點,之後用過比較兩者的根節點是否相等來判斷是否能夠成一個環。 接下來就是最簡單的最小生成樹以及並查集的程式碼了:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
public class mintree {
public static int n;//結點數
public static int m;//路徑數
public static int check[];
public static int count=0;
public static HashSet<node>set=new HashSet<node>();//儲存已經訪問過的路徑資訊
public static node[ ]list=new node[515556];//儲存路徑資訊,起點,終點,路徑長
public static int find(int x)//並查集中的並
{
return (check[x]==x)?x:(check[x]=find(check[x]));
}
public static void Kruskal()
{
set=new HashSet<node>();
for(int i=0;i<list.length;i++)
{
if(find(list[i].start)!=find(list[i].end))
{
count++ ;
set.add(list[i]);
check[find(list[i].start)]=find(list[i].end);
if(count==n-1)
break;
}
}
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
check=new int [n];
for(int i=0;i<n;i++)
check[i]=i;
list=new node[m];
for(int i=0;i<m;i++)
{
int n1=sc.nextInt();
int n2=sc.nextInt();
int n3=sc.nextInt();
node node1=new node(n1-1, n2-1, n3);
list[i]=node1;
}
Arrays.sort(list);//將路徑長從從小到大排序
Kruskal();
for(node value:set)
{
System.out.println((value.start+1)+"--->"+(value.end+1));
}
}
static class node implements Comparable<node>//建立一個內部類並且實現Comparable介面,這樣當使用Arrays.sort方法是就能直接排序了
{
int start;
int end;
int length;
public node(int start,int end,int length)
{
this.start=start;
this.end=end;
this.length=length;
}
@Override
public int compareTo(node o) {
// TODO Auto-generated method stub
return this.length-o.length;
}
}
}
作者很菜,如有不足,請指教。