最小產生樹—kruskal演算法和prim演算法

來源:互聯網
上載者:User

主要講解求解最小產生樹的兩種不同的貪心策略,最小產生樹的概念就不講解了,下面直接給出兩種演算法的理解。

在編程中通過結點的flag標記該結點屬於哪棵樹,開始時所有結點的flag大於零,若其所在邊被選擇為最小產生樹的邊,則把該結點的flag標記為相應的負數。下面結合圖講解:

 

                                                                                                      

其中紅色邊表示該邊的兩端結點在同一棵樹中,h、g、f結點在同一棵樹中,則h、g、f 結點的標示符flag都為-1;c、i結點在同一棵樹中且不是與h、g、f在同一棵樹中,則c、i結點的標示符flag為-2;其他結點的flag為大於零的整數。當選擇圖中的最小邊時,若邊的兩端結點的flag標誌為負值且相等,則表示該邊在最小產生樹中了,可以排除不會再被選中,中的:權值為1、2、2的三個邊。那麼權值最小的邊為4有三個,可以先選擇其中的任意一個:

1.若選擇邊的兩端結點為a、b,首先判斷a、b結點中的標示符flag都為正,表示a、b兩點在不同的樹中並且樹中只有自己。將兩個樹合并,即a、b結點標示符flag為-3

                                                                                                         

2. 選擇權值最小的邊,有兩個未被選的邊權值為4(因為邊的端結點為a、b,兩個端點的flag值為負且相等,表明該邊已被選為最小產生樹的邊),此次選擇到端點為e、f 的邊。由於f的標示符flag為負值,表明f和其他結點組成一棵樹,e的結點為正,表明其單獨構成一棵樹,直接把e結點構成的樹合并到 f 結點所在的樹中(把f 結點的flag賦值給e結點的flag,便可完成樹的合并)

                                                                                                      

3. 選擇權值最小的邊,只有一個未被選的權值為4的邊,端結點為c、f。c、f 的標示符flag都為負且不相等,一個為-2一個為-1。表明c和其他結點組成一棵樹,f 和其他結點組成一棵樹,並且是不同的兩棵樹。那麼要把這兩棵樹合并,做法:把c所在的樹中所有結點的flag 賦值為f 的標示符flag的值(即把c所在樹中的結點c、i的flag賦值為-1),這樣便完成兩棵樹的合并。

                                                                                                 

一直合并,知道所有的結點都在同一棵樹中,即所有的結點的標示符flag都為負值且相等。

Minspantree.h

#pragma once#include<iostream>#include<string>#include<vector>using namespace std;template<typename Comparable>struct Node                  //圖中的結點E{Comparable element;//結點的元素vector<Node<Comparable>*> next;        //結點的串連指標,指向多個結點vector<Node<Comparable>*> father;      //父親結點int flag;                              //主要用於Kruskal演算法標記該結點屬於那一棵樹Node(Comparable e,int f):element(e),flag(f){}};template<typename Comparable>struct Edge                //圖中邊{Node<Comparable>* N1; //結點1Node<Comparable>* N2; //結點2int weight;           //兩個結點間的權值Edge(Node<Comparable>* n1,Node<Comparable>* n2,int w):N1(n1),N2(n2),weight(w){}};template<typename Comparable>class graph{public:void insert(Comparable *a,int *matrix,int *w,int n);//a:圖中個結點的元素;matrix:鄰接矩陣                                                   //w為相連結點間的權值,n結點數void Kruskal();void Prim();private:vector<Node<Comparable>*> root;  //儲存每個結點的地址vector<Edge<Comparable>*> side;  //儲存每條邊的地址vector<Edge<Comparable>*> Mintree;//儲存最小產生樹的邊bool find(Edge<Comparable>* edge,int f);//Kruskal,判斷某邊的兩端結點是否在一顆樹中void changef(Node<Comparable>* t,int f);//Kruskal,將結點合并,};                                          //即把結點中的標示flag改為相等的數值,表示在同一棵樹中


 

Minspantree.cpp

#include "stdafx.h"#include"Minspantree.h"#include<iostream>#include<string>#include<vector>using namespace std;template<typename Comparable>void graph<Comparable>::insert(Comparable *a,int *matrix,int *w,int n)//實現圖的構建,包括結點和邊{for(int i=0;i<n;i++){Node<Comparable>* node=new Node<Comparable>(a[i],i+1);root.push_back(node);}Node<Comparable>* node=NULL;Node<Comparable>* temp=NULL;int k=0;for(int i=0;i<n;i++){node=root[i];for(int j=0;j<n;j++){if(matrix[n*i+j]!=0){temp=root[j];node->next.push_back(temp);temp->father.push_back(node);if(j>i){Edge<Comparable>* edge=new Edge<Comparable>(node,temp,w[k]);k=k+1;side.push_back(edge);}}}}}template<typename Comparable>void graph<Comparable>::Kruskal()  //Kruskal演算法實現最小產生樹{                                  //其中結點中的flag標示一個邊的兩端結點是否在同一棵樹中int en=side.size();          //圖中總共有多少條邊Edge<Comparable>* edge=NULL;for(int i=0;i<en;i++)        //排序,按邊權重升序排序。註:此處可以採用快排可減少排序的時間{for(int j=i;j<en;j++)if(side[i]->weight>side[j]->weight){edge=side[i];side[i]=side[j];side[j]=edge;}}int f=-1;edge=side[0];             //將權值最小的邊放入到樹中Mintree.push_back(edge);edge->N1->flag=f;edge->N2->flag=f;        //將edge兩端結點的標誌flag設定為同一個數,表明兩個結點在同一顆樹中for(int i=1;i<en;i++)     {edge=side[i];f=f-1;if(find(edge,f))     //如果edge兩個結點不是同時在同一顆樹中,則串連該條邊Mintree.push_back(edge);}cout<<"Kruskal演算法最小產生樹:"<<endl;int n=Mintree.size();int sum=0;for(int i=0;i<n;i++){edge=Mintree[i];cout<<"("<<edge->N1->element<<","<<edge->N2->element<<","<<edge->weight<<")"<<" ";sum+=edge->weight;}cout<<endl;cout<<"最小權值:"<<sum<<endl;}template<typename Comparable>bool graph<Comparable>::find(Edge<Comparable>* edge,int f){if(edge->N1->flag>0&&edge->N2->flag>0){edge->N1->flag=f;edge->N2->flag=f;return true;}else if(edge->N1->flag>0&&edge->N2->flag<0){edge->N1->flag=edge->N2->flag;return true;}else if(edge->N1->flag<0&&edge->N2->flag>0){edge->N2->flag=edge->N1->flag;return true;}else if(edge->N1->flag<0&&edge->N2->flag<0&&edge->N1->flag!=edge->N2->flag){changef(edge->N2,edge->N1->flag);return true;}elsereturn false;}template<typename Comparable> void graph<Comparable>::changef(Node<Comparable>* t,int f){int n=Mintree.size();int flag=t->flag;Node<Comparable>* n1=NULL;Node<Comparable>* n2=NULL;Edge<Comparable>* edge=NULL;for(int i=0;i<n;i++){edge=Mintree[i];n1=edge->N1;n2=edge->N2;if(n1->flag==flag)n1->flag=f;if(n2->flag==flag)n2->flag=f;}t->flag=f;}template<typename Comparable>   void graph<Comparable>::Prim()  //Prim演算法實現最小產生樹{Node<Comparable>* node=NULL;Edge<Comparable>* edge=NULL;Edge<Comparable>* result=new Edge<Comparable>(NULL,NULL,1000);Edge<Comparable>* temp=new Edge<Comparable>(NULL,NULL,1000);int en=side.size();int n=root.size();node=root[0];node->flag=-1;              //初始化一個根結點int k=0;while(k<n-1){for(int i=0;i<en;i++){edge=side[i];if(edge->N1->flag*edge->N2->flag<0&&edge->weight<result->weight){result=edge;}}if(result->N1->flag<0)result->N2->flag=result->N1->flag;elseresult->N1->flag=result->N2->flag;Mintree.push_back(result);result=temp;k=k+1;}cout<<"prim演算法最小產生樹:"<<endl;    n=Mintree.size();int sum=0;for(int i=0;i<n;i++){edge=Mintree[i];cout<<"("<<edge->N1->element<<","<<edge->N2->element<<","<<edge->weight<<")"<<" ";sum+=edge->weight;}cout<<endl;cout<<"最小權值:"<<sum<<endl;}


Algorithm-graph2.cpp

// Algorithm-graph2.cpp : 定義控制台應用程式的進入點。//主要是實現最小產生樹#include "stdafx.h"#include"Minspantree.h"#include"Minspantree.cpp"#include<string>#include<iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){graph<string> g;int n=9;int matrix[81]={0,1,0,0,0,0,0,1,0,                1,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,0,1,0,1,0,0,1,0,0,0,1,1,0};string a[9]={"a","b","c","d","e","f","g","h","i"};int w[14]={4,8,8,11,7,4,2,9,14,10,2,1,6,7};g.insert(a,matrix,w,n);g.Kruskal();g.Prim();return 0;}


 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.