ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

克鲁斯卡尔算法-公交站问题

2022-06-15 06:31:06  阅读:178  来源: 互联网

标签:int 克鲁斯 length edges 算法 edge 公交站 nodes def


1.背景

2.代码

package com.ldp.algorithm.demo05Kruskal;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 06/14 9:04
 * @description <P>
 * 克鲁斯卡尔算法-公交站问题
 * 1.找出所有边
 * 2.对边按照权值排序
 * 3.从小到大加入边(要求加入时不构成回路)
 * 是否构成回路的判定标准
 * 将要加入的边的"终点" 不相等,(这句话很抽象,难以使用文字表述,大家理解下面的代码吧)
 * 那么这个算法最核心,最难的点其实就是如何动态的获取"终端"的算法
 * </P>
 */
public class Test01 {

    @Test
    public void test01() {
        // 1.定义节点
        char[] nodes = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        // 2.使用矩阵表示节点间的距离
        // -1表示节点之间不通,0表示自己节点的距离,如A到A的距离为0
        int def = -1;
        int[][] nodeSpace = {
                // 'A', 'B', 'C', 'D', 'E', 'F', 'G'
                {0, 12, def, def, def, 16, 14},
                {12, 0, 10, def, def, 7, def},
                {def, 10, 0, 3, 5, 6, def},
                {def, def, 3, 0, 4, def, def},
                {def, def, 5, 4, 0, 2, 8},
                {16, 7, 6, def, 2, 0, 9},
                {14, def, def, def, 8, 9, 0}
        };
        MinTree minTree = new MinTree(nodes, nodeSpace);
        // minTree.printNodeSpace();
        // minTree.getEdgeBySpace();
        // minTree.printEdges();
        // minTree.sortEdges();
        // minTree.printEdges();
        minTree.kruskal();
        minTree.printEdgesResult();
    }
}

class MinTree {
    // 1.定义节点
    char[] nodes;
    // 2.使用矩阵表示节点间的距离
    // -1表示节点之间不通,0表示自己节点的距离,如A到A的距离为0
    int def = -1;
    // 节点间的距离关系
    int[][] nodeSpace;
    // 边,应排序
    Edge[] edges;
    // 边的条数
    int edgeNum;
    // 实际选出来的最优边
    Edge[] edgesResult;

    /**
     * 采用复制的方式初始化对象
     *
     * @param nodes
     * @param nodeSpace
     */
    public MinTree(char[] nodes, int[][] nodeSpace) {
        int length = nodes.length;
        // 节点处理
        char[] nodesNew = new char[length];
        for (int i = 0; i < length; i++) {
            nodesNew[i] = nodes[i];
        }
        this.nodes = nodesNew;
        // 位置距离处理和有效边的条数
        int[][] nodeSpaceNew = new int[length][length];
        int num = 0;
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < length; j++) {
                nodeSpaceNew[i][j] = nodeSpace[i][j];
                if (i < j && nodeSpace[i][j] != def) {// 统计边的条数
                    num++;
                }
            }
        }
        this.nodeSpace = nodeSpace;
        this.edgeNum = num;
    }

    /**
     * 打印矩阵
     */
    public void printNodeSpace() {
        for (int[] ints : nodeSpace) {
            System.out.println(Arrays.toString(ints));
        }
    }

    /**
     * 根据位置空间获取边
     */
    public void getEdgeBySpace() {
        if (edges != null) {
            return;
        }
        Edge[] edgesNew = new Edge[edgeNum];
        // 遍历位置空间数组
        int length = nodes.length;
        int num = 0;
        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                int weight = nodeSpace[i][j];
                if (weight == def) {// 说明不通,不是有效边
                    continue;
                }
                Edge edge = new Edge();
                edge.weight = weight;
                edge.start = i;
                edge.end = j;
                edge.name = String.valueOf(nodes[i]) + String.valueOf(nodes[j]);
                edgesNew[num] = edge;
                num++;
            }
        }
        this.edges = edgesNew;
    }

    /**
     * 打印边
     */
    public void printEdges() {
        System.out.println("================edges 打印开始======================");
        for (Edge edge : edges) {
            System.out.println(edge);
        }
        System.out.println("================edges 打印结束======================");
    }

    /**
     * 对边排序,从小到大
     */
    public void sortEdges() {
        for (int i = 0; i < edgeNum - 1; i++) {
            for (int j = i + 1; j < edgeNum; j++) {
                int weightI = edges[i].weight;
                int weightJ = edges[j].weight;
                if (weightI > weightJ) {
                    Edge temp = edges[i];
                    edges[i] = edges[j];
                    edges[j] = temp;
                }
            }
        }
    }

    /**
     * 获取第i个元素的终点下标
     *
     * @param ends
     * @param i
     * @return
     */
    public int getEndIndex(int[] ends, int i) {
        // 注意这里是while循环,对于链接成穿的边会循环找,如C-D-E-F这三个边形成后,C,D,E的终点都是F
        while (ends[i] != 0) {
            i = ends[i];
        }
        return i;
    }

    /**
     * 克鲁斯卡尔算法实现
     */
    public void kruskal() {
        // 生成边
        getEdgeBySpace();
        // 排序
        sortEdges();
        // 遍历边依次加入到结果集
        Edge[] edgesResult = new Edge[nodes.length - 1];
        int num = 0;
        // 记录终点
        int[] ends = new int[nodes.length];
        for (int i = 0; i < edgeNum; i++) {
            Edge edge = edges[i];
            int startIndex = getEndIndex(ends, edge.start);
            int endIndex = getEndIndex(ends, edge.end);
            if (startIndex == endIndex) {
                // 同一个终点会构成回路,不加入
                continue;
            }
            System.out.println("添加边:num=" + num + ",edge=" + edge);
            // 加入边
            edgesResult[num++] = edge;
            // 加入终点
            // ends[edge.start] = endIndex;
            ends[startIndex] = endIndex;
        }
        this.edgesResult = edgesResult;
    }

    /**
     * 打印边
     */
    public void printEdgesResult() {
        System.out.println("================edges 打印开始======================");
        for (Edge edge : edgesResult) {
            System.out.println(edge);
        }
        System.out.println("================edges 打印结束======================");
    }
}

class Edge {
    String name;
    int start;
    int end;
    int weight;

    @Override
    public String toString() {
        return "=>" + name + "=" + weight;
    }
}

 

完美!

标签:int,克鲁斯,length,edges,算法,edge,公交站,nodes,def
来源: https://www.cnblogs.com/butingxue/p/16377034.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有