圖的最小生成樹(java實現)

1.圖的最小生成樹(貪心算法)

我兩個算法的輸出都是數組表示的,當前的索引值和當前索引對應的數據就是通路,好比parent[2] = 5;即2和5之間有一個通路,第二個可能比較好理解,第一個有點混亂java

是什麼?

將一個有權圖中的 全部頂點 都鏈接起來,並保證鏈接的邊的 總權重最小,即最小生成樹,最小生成樹不惟一算法

爲何?

傳入鄰接矩陣,返回能夠生成最小生成樹的數據數組

咱們有兩種方式生成圖的最小生成樹1.普里姆(Prim)算法2.克魯斯卡爾(Kruskal)算法數據結構

怎樣作?

圖片參考博客:http://www.javashuo.com/article/p-eolenwad-hz.htmlide

下面是普里姆算法的最小生成樹this

 

下面是克魯斯卡爾算法的最小生成樹:spa

圖的鄰接矩陣表示法(無向圖,上三角矩陣).net

int[][] arr = new int[][]{
{-1, 4, 0, 0, 0, 0, 0, 8, 0},
{0, -1, 8, 0, 0, 0, 0, 11, 0},
{0, 0, -1, 7, 0, 4, 0, 0, 2},
{0, 0, 0, -1, 9, 14, 0, 0, 0},
{0, 0, 0, 0, -1, 10, 0, 0, 0},
{0, 0, 0, 0, 0, -1, 2, 0, 0},
{0, 0, 0, 0, 0, 0, -1, 1, 6},
{0, 0, 0, 0, 0, 0, 0, -1, 7},
{0, 0, 0, 0, 0, 0, 0, 0, -1}
};

1.普里姆算法(加點法)code

需求:求出最小生成樹的權值blog

輸入參數:二維數組arr(鄰接矩陣),列表list(存放已經被加入的點),整型sum(存放權值)

輸出參數:整型數組parent

1)先找一個起點,這個起點爲任意一點,放入list中

2)若是list中不包含所有節點,進入循環

  1>遍歷list中節點,查找不存在list中的鄰接節點的最小值,記錄下begin和end

  2>將begin和end放入數組中,較小值節點賦值給較大值所在數組位置
3)返回parent

 

 實現:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 普里姆(Prim)算法
 *
 * @author Xiong YuSong
 * 2019/3/22 16:02
 */
public class Prim {

    public static void main(String[] args) {
        int[][] arr = new int[][]{
                {-1, 4, 0, 0, 0, 0, 0, 8, 0},
                {0, -1, 8, 0, 0, 0, 0, 11, 0},
                {0, 0, -1, 7, 0, 4, 0, 0, 2},
                {0, 0, 0, -1, 9, 14, 0, 0, 0},
                {0, 0, 0, 0, -1, 10, 0, 0, 0},
                {0, 0, 0, 0, 0, -1, 2, 0, 0},
                {0, 0, 0, 0, 0, 0, -1, 1, 6},
                {0, 0, 0, 0, 0, 0, 0, -1, 7},
                {0, 0, 0, 0, 0, 0, 0, 0, -1}
        };
        List<Integer> list = new ArrayList<>();
        //先將0放置在list中
        list.add(0);
        int begin = 0, end = 0, weight;
        int[] parent = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            parent[i] = -1;
        }
        while (list.size() < arr.length) {
            weight = Integer.MAX_VALUE;
            for (Integer row : list) {
                for (int i = 0; i < arr.length; i++) {
                    if (!list.contains(i)) {
                        if (i >= row + 1) {
                            if (arr[row][i] > 0 && arr[row][i] < weight) {
                                begin = row;
                                end = i;
                                weight = arr[row][i];
                            }
                        } else if (i <= row - 1) {
                            //我這裏只用了上三角矩陣,因此這裏須要多此一舉寫這一部分
                            if (arr[i][row] > 0 && arr[i][row] < weight) {
                                begin = row;
                                end = i;
                                weight = arr[i][row];
                            }
                        }
                    }
                }
            }
            list.add(end);
            parent[end] = begin;
        }
        System.out.println(Arrays.toString(parent));
    }
}

 

2.克魯斯卡爾算法(加邊法)

需求:求出最小生成樹的權值

構建類:Edge<begin,end,weight>三元組,根據weight(權值)排序

輸入參數:存放有Edge的列表list,並查集parent

輸出參數:並查集parent(最小生成樹的數組表現形式)

原理:貪心算法的實現,程序中使用了並查集(判斷兩個集合中是否存在相同的數據)這種特殊的數據結構,使用數組實現

1)建立一個三元組<起始點,終止點,權值>,將鄰接矩陣中數據放入三元組中,再放入list中,根據權值進行排序

2)建立變量count=0,整型數組parent

3)若是list中還存在值,則進行循環

  1>判斷begin和end是否存在於不一樣的集合中(判斷是否在同一棵樹中,即判斷當前節點在並查集parent中的根節點是否爲同一個)

  2>若是存在不一樣的集合中,則將較小值節點賦值給較大值所在數組位置,較小值節點爲較大值節點的父節點

4)返回parent

實現:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author Xiong YuSong
 * 2019/3/22 17:04
 */
class Edge implements Comparable<Edge> {
    //起始點
    private int begin;
    //終止點
    private int end;
    //權值
    private int weight;

    public Edge(int begin, int end, int weight) {
        this.begin = begin;
        this.end = end;
        this.weight = weight;
    }

    public int getBegin() {
        return begin;
    }

    public void setBegin(int begin) {
        this.begin = begin;
    }

    public int getEnd() {
        return end;
    }

    public void setEnd(int end) {
        this.end = end;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    @Override
    public int compareTo(Edge o) {
        if (o.weight > this.weight) {
            return -1;
        } else {
            return 1;
        }
    }
}

public class Kruskal {

    public static void main(String[] args) {
        //默認以a爲根節點的最小生成樹
        List<Edge> list = new ArrayList<>();
        int[][] arr = new int[][]{
                {-1, 4, 0, 0, 0, 0, 0, 8, 0},
                {0, -1, 8, 0, 0, 0, 0, 11, 0},
                {0, 0, -1, 7, 0, 4, 0, 0, 2},
                {0, 0, 0, -1, 9, 14, 0, 0, 0},
                {0, 0, 0, 0, -1, 10, 0, 0, 0},
                {0, 0, 0, 0, 0, -1, 2, 0, 0},
                {0, 0, 0, 0, 0, 0, -1, 1, 6},
                {0, 0, 0, 0, 0, 0, 0, -1, 7},
                {0, 0, 0, 0, 0, 0, 0, 0, -1}
        };
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[i][j] > 0) {
                    list.add(new Edge(i, j, arr[i][j]));
                }
            }
        }
        Collections.sort(list);
        //數組中每個節點都只知道他的父節點是什麼,-1表示不存在父節點,0位置是根節點
        int[] parent = new int[arr.length];
        for (int i = 1; i < arr.length; i++) {
            parent[i] = -1;
        }
        int m = 0, n = 0;
        for (Edge edge : list) {
            //尋找這兩個點有沒有相同的父節點
            m = find(parent, edge.getBegin());
            n = find(parent, edge.getEnd());
            if (m != n && parent[edge.getEnd()]>0) {
                parent[edge.getEnd()] = edge.getBegin();
            }
        }
        System.out.println(Arrays.toString(parent));
    }

    private static int find(int[] parent, int ch) {
        while (parent[ch] > 0) {
            ch = parent[ch];
        }
        return ch;
    }
}
相關文章
相關標籤/搜索