Kruskal算法

思路有參考:html

http://data.biancheng.net/view/41.htmlnode

 

思路;ios

源代碼見: https://github.com/nxkjwbxewudh/Kruskalgit

edge[MAX]保存全部的邊,每條邊存儲起始結點、終止結點和權重;github

先把全部邊按照升序排序,這裏用到了sort,須要#include<algorithm> ;數組

從edge[MAX]裏(就是排序後的數組)以此取出一條邊,首先判斷這條邊能不能加入最小生成樹(記得另外定義一個變量minTree[MAX]保存結果);函數

   判斷方法:oop

   新建一個輔助數組,保存全部頂點,一開始,每一個頂點都有一個獨一無二的set值,用來表示他們的終點;spa

   由於造成迴路的條件就是取出來的當前這條邊的兩個頂點的終點相同,也就是set值相同;.net

   因此每次取出一條邊,就要判斷是否兩頂點set值相等;

   不相等的話就能夠添加到最小生成樹中。每次添加了一個新的邊就要修改一個頂點的set值;

#include<iostream>
#include<algorithm>     //爲了使用sort函數對全部邊按照權重進行升序排序
#include<stdlib.h>
#include<string>
#include<fstream>
using namespace std;

#define MAX 100
struct node{
   char startNode;
   char endNode;
   int  weight;
}edge[MAX]={
    {'a','b',36},
    {'a','c',18},
    {'a','d',27},
    {'c','d',54},
    {'c','e',60},
    {'b','e',40},
    {'e','f',50},
    {'b','f',60},
    {'b','c',24}
};
struct helpGroup
{
   char nodeName;
   int  rootNodeSet;      //若是選擇的這條邊的頂點的終點結點是同一個set,那麼就會造成迴路   
}assistGroup[MAX]={
    {'a',1},
    {'b',2},
    {'c',3},
    {'d',4},
    {'e',5},
    {'f',6}
};

/**
 * 用於打印結果
 * 輸入:minTree邊的條數和minTree數組
 * 輸出:打印每條邊,形式爲start-end,而且返回總權值,函數返回類型void
 * **/
void printMyTree(int n, node given[], int sum){
   int i = 0;
   cout<<"最小生成樹爲:"<<endl;
   for(i=0;i<n;i++){
      cout<<given[i].startNode<<" - "<<given[i].endNode<<endl;
   }
   cout<<"最小生成樹總權值爲:"<<sum<<endl;
}

/**
 * 用於判斷是否會造成迴路
 * 輸入:n,一條邊的初始/末尾結點
 * 輸出:這個節點在輔助數組中的位置,函數返回類型int
 * **/
int getNodePlace(int n, char nodeName){
    int i=0;
    for(i=0;i<n;i++){
       if(assistGroup[i].nodeName == nodeName){
          return i;
       }
    }
    return -1;
}

/**
 * 修改當前這條邊上的某一個結點的set值
 * 遍歷輔助數組,遇到set值和某個結點set值相等的話,就更新另外一個結點的set
 * 若是這兩個節點都不在當前的樹中,就把終點結點的set賦值給起始節點的set
 * 輸入:n,init,end
 * 輸出:只是修改,函數返回類型void
 * **/
void changeSet(int n, int start, int end){
   int i=0;
   for(i=0;i<n;i++){
      if(assistGroup[start].rootNodeSet == assistGroup[i].rootNodeSet){
         assistGroup[end].rootNodeSet = assistGroup[start].rootNodeSet;
         break;
      }
      if(assistGroup[end].rootNodeSet == assistGroup[i].rootNodeSet){
         assistGroup[start].rootNodeSet = assistGroup[end].rootNodeSet;
         break;
      }
   }
   assistGroup[start].rootNodeSet = assistGroup[end].rootNodeSet;
}

bool cpm(node x, node y){
   if(x.weight==y.weight){
      return x.startNode<y.startNode;
   }
   else{
      return x.weight<y.weight;
   }
}

int main(){
   int sum=0;                            //總權值
   int nodeNum=0;
   int edgeNum=0;      
   cout<<"請輸入節點個數和邊的條數"<<endl;
   cin>>nodeNum>>edgeNum;              //得到頂點數目和邊數
   int n=edgeNum;                      //n表明邊數
   
 /*初始化最小生成樹,全部邊按權值排序*/
   int treeCount=0;                    //最小生成樹結點個數
   node minTree[MAX];                  //用於保存結果最小生成樹
   sort(edge,edge+n,cpm);              //將全部邊按照權值升序排序,並取代edge數組
   //int k=0;
   /*cout<<"edge升序排序以後的結果"<<endl;
   for(k=0;k<n;k++){
       cout<<edge[k].startNode<<"->"<<edge[k].endNode<<endl;
   }
   */

 /*從edge裏選一條邊,若是這條邊的兩個頂點的set值相等,表示會造成迴路*/
   int i=0;
   int init=0;
   int end=0;
   int initSet=0;
   int endSet=0;
   for(i=0;i<n;i++){
      init = getNodePlace(nodeNum, edge[i].startNode) ;
      end  = getNodePlace(nodeNum, edge[i].endNode) ;
      initSet = assistGroup[init].rootNodeSet;
      endSet = assistGroup[end].rootNodeSet;
      if((init==-1)||(end==-1)){
         cout<<"程序出錯,應該是初始化問題"<<endl;
      }
      else
      {
         if(initSet==endSet){
            continue;//會造成迴路
         }
         else
         {
            //能夠加入樹中
            minTree[treeCount] = edge[i];
            treeCount++;
            sum = sum + edge[i].weight;
            //修改原來這條邊上結點的set值,使之等於當前最新的樹上的set值
            changeSet(edgeNum,init,end);    
            if(treeCount == (nodeNum-1)){
               break;
            }
         }
         
      }
      
   }//end_of_big_loop

   printMyTree(treeCount,minTree,sum);
   system("pause");
   return 0;
}

 

 

 

 

 

 源代碼見: https://github.com/nxkjwbxewudh/Kruskal

相關文章
相關標籤/搜索