1. 程式人生 > >基於矩陣實現的最小生成樹演算法

基於矩陣實現的最小生成樹演算法

1.最小生成樹

Wikipedia中最小生成樹(Minimum Spanning Tree)的定義如下:
A minimum spanning tree is a spanning tree of a connected, undirected graph. It connects all the verticestogether with the minimal total weighting for its edges.
但是,在本文中,我們主要介紹Prim演算法,Prim演算法同樣可以在Wikipedia中找到:

In computer science, Prim's algorithm is a greedy algorithm that finds a minimum spanning tree for a weighted undirected graph. This means it finds a subset of the edges that forms a tree that includes every vertex, where the total weight of all the edges in the tree is minimized. The algorithm operates by building this tree one vertex at a time, from an arbitrary starting vertex, at each step adding the cheapest possible connection from the tree to another vertex.

2.傳統演算法

2.1演算法描述

Prim的演算法思想很簡單:
  1. 從圖中任選一個結點,放入最小生成樹集合中,
  2. 重複操作:找最小生成樹集合中所有結點的最近鄰接點,然後再放入到最小生成樹集合中,
  3. 當訪問完所有結點,即找到最小生成樹。

下面對演算法的圖例描述:


2.2演算法實現

Python實現如下:
import numpy as np

def prim(adjacencyMat, dimension, startVertex = 0):
    visited = np.zeros(dimension)
    distance = np.zeros(dimension)
    for i in range(dimension):
        distance[i] = np.inf
    tree = []
    tree.append(startVertex)
    visited[startVertex] = 1
    
    currentVertex = startVertex
    while not(len(tree) == dimension):
        for i in range(dimension):
            if not(adjacencyMat[currentVertex, i] == 0):
                if (visited[i] == 0) and (distance[i] > adjacencyMat[currentVertex, i]):
                    distance[i] = adjacencyMat[currentVertex, i]
#                     tree.append(i)
                    
        minDist = np.inf
        for i in range(dimension):
            if(visited[i] == 0) and (distance[i] < minDist):
                minDist = distance[i]
                currentVertex = i
        tree.append(currentVertex)
        visited[currentVertex] = 1
    print(tree)
    
if __name__ == "__main__":
    adjacencyMat = np.array([[0,2,3,0,1],
                             [0,0,0,0,7],
                             [0,0,0,3,0],
                             [0,0,0,0,0],
                             [0,0,0,4,0]])   
    dimension = 5
    prim(adjacencyMat, dimension)

3.基於矩陣的實現

3.1演算法描述

既然要採用矩陣的方式,那麼自然要用到鄰接矩陣,鄰接矩陣的定義如下:

同時,我們用一個向量s表示訪問過的點集S,向量s定義:


另外,我們還需要一個向量d儲存向量s中每個點對應的距離值,向量d定義:


假設有一個圖,有5個點如:


那麼其鄰接矩陣是:


假設把點1作為起始點,那麼起始向量是:

向量d初始是:

演算法思想是,當向量s不全為無窮大(即結點沒有訪問完)時,重複以下三步:

  1. 計算argmin(s+d)。即取出s+d的最小值對應的點u的標記或索引。
  2. 把點u在向量s中對應位置的值改為無窮大。
  3. 計算表示點u到其他結點的距離,此時計算點u到點v的最小距離,如果點v在集合S中,那麼點u到點v的距離是0;如果點v不在集合S中,那麼求點u到點v的最小距離。如
    ,那麼,即對應索引位置去最小值。

3.2演算法實現

Python實現如下:
from numpy.random import rand
import numpy as np

def init(dimension, startVertex = 0):
    mat = rand(dimension, dimension)
    mat[(rand(dimension) * dimension).astype(int), (rand(dimension) * dimension).astype(int)] = np.inf
    vertexVec = np.zeros(dimension)
    for i in range(dimension):
        mat[i, i] = 0
    vertexVec[startVertex] = np.inf
    distanceVec = mat[0, :]
    return mat, vertexVec, distanceVec

def minSpanningTree(adjacencyMat, vertexVec, distanceVec, startVertex, dimension):
    treeVec = []
    treeVec.append(startVertex)
    distanceVec = list(distanceVec)
    while(min(vertexVec) == 0):
        vertexId = distanceVec.index(min(distanceVec + vertexVec))
        vertexVec[vertexId] = np.inf
        treeVec.append(vertexId)
        for j in range(dimension):
            if adjacencyMat[vertexId, :][j] < distanceVec[j]:
                distanceVec[j] = adjacencyMat[vertexId, :][j]
    print(treeVec)

if __name__ == "__main__":
    dimension = 5
    startVertex = 0
    adjacencyMat, vertexVec, distanceVec = init(dimension, startVertex)
    adjacencyMat1 = np.array([[0,           2,     3, np.inf,      1],
                             [np.inf,      0, np.inf, np.inf,      7],
                             [np.inf, np.inf,      0,      3, np.inf],
                             [np.inf, np.inf, np.inf,      0, np.inf],
                             [np.inf, np.inf, np.inf,      4,      0]])
    distanceVec1 = adjacencyMat1[0, :]
    treeVec = []
    treeVec.append(startVertex)
    minSpanningTree(adjacencyMat1, vertexVec, distanceVec1, startVertex, dimension)