基於並查集+Kruskal算法的matlab程序及最小生成樹繪圖

學了一天最小生成樹,稍稍總結一下,這是第一篇

  1. kruskal算法

    關於kruskal算法已有大量的資料,不再贅述,算法流程爲:

    • 得到鄰接矩陣和權值;
    • 初始化,連接距離最小的兩點;
    • 連接距離次小的兩點,如果形成迴路則取消連接;重複上述連接步驟,直到所有n個節點被n-1條邊連接成樹。
  2. 並查集

    關於並查集的可以看一下這篇:《一個很有意思的並查集詳解》
    下面給出兩個子函數,一個用於尋找根節點(RootNode),一個用於合併(MergeNode)。第二個函數加入了壓縮選項,壓縮的話計算量小一些,默認爲壓縮。
    需要注意的是,並查集有很多的應用,kruskal只是冰山一角。

%% 並查集
% Node = RootNode(Node,Father)
% 輸入:Node:需要查詢的節點
%       Father:記錄父節點的向量
% 輸出:父節點
function Node = RootNode(Node,Father)  % 找到根結點
    for i=1:length(Node)
        while(Node(i)~=Father(Node(i)))
            Node(i) = Father(Node(i));
        end
    end
end
%% 並查集
% Father = MergeNode(Node1,Node2,Father)
% 輸入:Node1:節點1
%       Node2:節點2
%       Father:父節點向量
%       CompressOption:壓縮選項,默認爲壓縮
% 輸出:Father:新的父節點
function Father = MergeNode(Node1,Node2,Father,CompressOption)
if nargin == 3
    CompressOption = 1;
end
RootNode1 = RootNode(Node1,Father);
if CompressOption  % 採取壓縮操作
    while(Node1~=RootNode1)  % 壓縮Node1所在的集合
        t = Father(Node1);
        Father(Node1) = RootNode1;
        Node1 = t;
    end
    while(Node2~=Father(Node2))    % 壓縮Node2所在的集合
        t = Father(Node2);
        Father(Node2) = RootNode1; % 全部改變爲Node1的根結點
        Node2 = t;
    end
    Father(Node2) = RootNode1; % 改變根結點
else
    Father(RootNode(Node2,Father)) = RootNode1; % 改變根結點
end

end

主函數:

%% 用Kruskal算法求解最小生成樹
function MST = Kruskal(Distance)
%% 開始計算
[Weight,Pos] = sort(Distance(find(triu(Distance)~=0)));
Num = max(find(~isinf(Weight)));
NumP = size(Distance);
Father = 1:NumP;
MST = [];
for i=1:Num
    [Node1,Node2] = GetSquarePos(Pos(i),NumP);
    if RootNode(Node1,Father) ~= RootNode(Node2,Father)
        Father = MergeNode(Node1,Node2,Father,0);
        MST = [MST;[Node1 Node2]];
        if size(MST,1) == NumP-1  % 如果樹已滿,就沒有必要繼續計算了
            break
        end
    end
end

%% 繪圖
DrawMST(P,MST,0.08);
end

這裏用到一個子函數GetSquarePos:

function [Node1,Node2] = GetSquarePos(pos,Dim)  % 輸入向量中的位置,輸出矩陣中的位置
    S = cumsum([0:Dim-1])-pos;
    Node1 = min(find(S>=0));         % 列數
    Node2 = pos-sum(0:Node1-2);      % 行數
end

該函數用於找到每條邊對應的兩個節點。

還有一個作圖函數DrawMST:

%% 繪製最小生成樹
function h = DrawMST(points,MST,deviation)  % MSTMinimumSpanningTree
if nargin == 2
    deviation = 0.01;
end
if size(points,2) >3
    error('本程序只能繪製二維或者三維圖~~')
end
%% 開始作圖
if size(points,2) == 2  % 二維數據
    for i=1:size(MST,1) % 樹
        plot(points(MST(i,:),1),points(MST(i,:),2),'r-o','LineWidth',1.5,...
            'MarkerSize',5,'MarkerFaceColor','b'); hold on;
    end
    for i=1:size(points,1) 
        text(points(i,1)+deviation,points(i,1),num2str(i));
    end 
    title('最小生成樹示意圖')
    xlabel('x'), ylabel('y')
    h = gca;
else  % 三維數據
    for i=1:size(MST,1) % 樹
        plot3(points(MST(i,:),1),points(MST(i,:),2),points(MST(i,:),3),'r-o','LineWidth',1.5,...
            'MarkerSize',5,'MarkerFaceColor','b'); hold on;
    end
    for i=1:size(points,1) 
        text(points(i,1),points(i,2),points(i,3)+deviation,num2str(i),'color','g');
    end 
    grid on;
    set(gca,'color','k')
    title('最小生成樹示意圖')
    xlabel('x'), ylabel('y'), zlabel('z')
    h = gca;
end
axis equal
end

該函數即可用於二維作圖,也可用於三維。

輸入參數:

P = [6.4889    5.5314    4.4938
    7.0347    5.7275    5.5554
    6.7269    7.0984    5.8441
    5.6966    5.7221    6.2761
    6.2939    6.7015    5.7388
    5.2127    3.9482    6.4434
    6.8884    5.6462    6.3919
    4.8529    5.1764    4.7493
    4.9311    4.4229    5.0520
    5.1905    6.5080    5.2589];
Distance = squareform(pdist(P));  % 不解釋

運行結果:

ans =

     5     3
     9     8
     7     2
     7     4
     2     1
    10     5
     5     2
    10     8
     9     6

截圖:

MST

關於Prime的見另外一篇(上面的程序有些有些囉嗦,再接再勵~)

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章