算法分析-最小生成树

定义:图的生成树是它的一棵含有其所有顶点的无环连通子图,一副加权无向图的最小生成树它的一棵权值最小的生成树。

性质:

  1. 用一条边连接树中的任意两个顶点都会产生一个新的环
  2. 从树中删除任意一条边,将会得到两棵独立的树

切分定理:

切分:将图的所有顶点按照某些规则分为两个非空且没有交集的集合

横切边:连接两个属于不同集合的顶点的边

在一副加权图中,给定任意的切分,它的横切边中权重最小者必然属于图中的最小生成树。

Prim算法的切分规则:

把最小生成树中的顶点看做是一个集合,把不在最小生成树中的顶点看做是另外一个集合。

代码:

package com.chenqing.test.digraph;

import com.chenqing.test.linearList.queue.IndexMinPriorityxQueue;
import com.chenqing.test.linearList.queue.Queue;

/**
 * @author 陈沁
 * Prim算法实现最小生成树,主要使用的是贪心算法里的切分定理
 */
public class PrimMST {
    private Edge[] edgeTo;
    private Double[] weights;
    private boolean[] marked;
    private IndexMinPriorityxQueue<Double> qp;

    public PrimMST(EdgeWeightedGraph graph) {
        this.edgeTo = new Edge[graph.getV()];
        this.weights = new Double[graph.getV()];
        this.marked = new boolean[graph.getV()];
        this.qp = new IndexMinPriorityxQueue<Double>(graph.getV());
        for (int i = 0; i < this.weights.length; i++) {
            this.weights[i] = Double.POSITIVE_INFINITY;
        }
        this.weights[0] = 0.0;
        this.qp.insert(0, 0.0);
        while(!this.qp.isEmpty()){
            int minIndex = this.qp.delMin();
            this.visit(graph, minIndex);
        }
    }

    private void visit(EdgeWeightedGraph graph, int v){
        this.marked[v] = true;
        for (Edge e : graph.adj(v)) {
            int w = e.other(v);
            if(marked[w]){
                continue;
            }
            if(e.getWeight() < weights[w]){
                edgeTo[w] = e;
                weights[w] = e.getWeight();
                if(qp.contains(w)){
                    qp.changeItem(w, weights[w]);
                }else{
                    qp.insert(w, weights[w]);
                }
            }
        }
    }

    public Queue<Edge> edges(){
        Queue<Edge> edges = new Queue<>();
        for (int i = 0; i < this.edgeTo.length; i++) {
            if(this.edgeTo[i] != null){
                edges.enqueue(this.edgeTo[i]);
            }
        }
        return edges;
    }
}

kruskal算法:

package com.chenqing.test.digraph;

import com.chenqing.test.linearList.queue.MinPriorityQueue;
import com.chenqing.test.linearList.queue.Queue;
import com.chenqing.test.uf.UfTree;

/**
 * @author 陈沁
 * Kruskal算法实现最小生成树,主要使用的是贪心算法里的切分定理
 */
public class KruskalMST {
    private Queue<Edge> edges; // 保存最小生成树的所有边
    private UfTree uf; // 索引代表顶点,可以判断两个顶点是否在一颗树中,可以合并两个顶点到一颗树中
    private MinPriorityQueue<Edge> minPriorityQueue; // 最小优先队列,存储图中的所有边

    public KruskalMST(EdgeWeightedGraph graph) {
        this.edges = new Queue<Edge>();
        this.uf = new UfTree(graph.getV());
        this.minPriorityQueue = new MinPriorityQueue<>(graph.getE() + 1);
        for (Edge edge : graph.edges()) {
            minPriorityQueue.insert(edge);
        }
        while (!minPriorityQueue.isEmpty() && edges.size() <= graph.getV() - 1){
            Edge edge = minPriorityQueue.delMin();
            int either = edge.either();
            int other = edge.other(either);
            if(uf.connected(either, other)){
                continue;
            }
            edges.enqueue(edge);
            uf.union(either, other);
        }
    }

    public Queue<Edge> edges(){
        return edges;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值