【算法基础实验】图论-构建加权无向图

构建加权无向图

理论基础

在图论中,加权无向图是一种每条边都分配了一个权重或成本的图形结构。这种类型的图在许多实际应用中都非常有用,如路由算法、网络流量设计、最小生成树和最短路径问题等。

加权无向图的基本特征

  1. 顶点和边
    • 顶点(Vertex): 图中的节点,可以表示交叉点、位置点或网络中的节点等。
    • 边(Edge): 连接顶点的线,无向边意味着连接的顶点间没有方向性的区别。
  2. 权重
    • 每条边都有一个权重(或成本、长度),这个权重是一个数值,代表了从一个顶点到另一个顶点的"成本"。
    • 权重可以表示多种含义,如距离、时间、消耗或任何其他度量标准。

存储加权无向图

加权无向图通常可以通过以下几种数据结构来存储和表示:

  1. 邻接矩阵
    • 使用二维数组来表示顶点之间的连接关系,矩阵中的每个元素代表边的权重。如果两个顶点之间没有直接连接,则该位置通常用一个特殊值(如无穷大或null)来表示。
  2. 邻接表
    • 每个顶点都对应一个列表,列表中存储了与该顶点直接相连的其他顶点及相应的权重。这种表示方法更加节省空间,尤其是在稀疏图中。
  3. 边的列表
    • 维护一个所有边的列表,每条边由一对顶点和一个权重组成。

图的操作

操作加权无向图常见的算法包括但不限于:

  1. 最小生成树(MST)
    • 寻找一种方式,通过树形结构连接图中的所有顶点,使得所有边的权重总和最小。常用算法包括Kruskal算法和Prim算法。
  2. 最短路径
    • 寻找顶点间的最短路径,即路径上的权重总和最小。常用算法包括Dijkstra算法和Floyd-Warshall算法。
  3. 网络流量优化
    • 在网络图中,寻找最优的数据流方式,使得成本最低或效率最高。

应用实例

加权无向图的应用非常广泛,例如:

  • 交通网络:道路或铁路网中的路径规划,权重可以是距离、时间或通行费用。
  • 电信网络:数据包的传输路径优化,权重可能是延迟或带宽。
  • 物流配送:货物配送路线的优化,权重可能包括距离和成本。
  • 资源分配:如电网中电力的分配。

加权无向图的研究和应用提供了一种强大的工具,可以解决实际中的许多优化和规划问题。在算法和数据结构的领域中,理解并有效使用这些工具是非常重要的。

数据结构和实验数据

代码实现

myEdge

java 复制代码
public class myEdge implements Comparable<myEdge>
{
    private final int v;
    private final int w;
    private final double weight;

    public myEdge(int v,int w,double weight){
        this.v = v;
        this.w = w;
        this.weight = weight;
    }
    public double weight()
    {return weight;}

    public int either()
    { return v;}

    public int other(int vertex)
    {
        if(vertex == v) return w;
        else if(vertex == w) return v;
        else throw new IllegalArgumentException("Invalid vertex");
    }
    public int compareTo(myEdge that)
    {
        if(this.weight()<that.weight()) return -1;
        else if(this.weight()>that.weight()) return 1;
        else return 0;
    }
    public String toString()
    { return String.format("%d-%d %.2f",v,w,weight);}
}

这段代码定义了一个名为 myEdge 的类,代表加权无向图中的一条边。类实现了 Comparable 接口,允许边对象之间进行比较,这通常用于算法中需要对边进行排序的情况,例如在构建最小生成树时。以下是对该类中每个部分的详细解释:

类定义和字段

java 复制代码
public class myEdge implements Comparable

这段代码定义了一个名为 myEdge 的类,代表加权无向图中的一条边。类实现了 Comparable 接口,允许边对象之间进行比较,这通常用于算法中需要对边进行排序的情况,例如在构建最小生成树时。以下是对该类中每个部分的详细解释:

类定义和字段

java 复制代码
public class myEdge implements Comparable

这段代码定义了一个名为 myEdge 的 Java 类,用于表示加权无向图的一条边。这个类实现了 `Comparable

这段代码定义了一个名为 myEdge 的 Java 类,用于表示加权无向图的一条边。这个类实现了 Comparable 接口,使得边可以根据权重进行排序,这是在图算法中常见的需求,特别是在最小生成树和最短路径算法中。

类字段

  • vw :这两个 private final int 类型的字段代表边连接的两个顶点。final 表明一旦边被创建,这两个顶点不可更改。
  • weight :这是一个 private final double 类型的字段,存储边的权重。同样,final 表示权重在创建后不可更改。

构造函数

java 复制代码
public myEdge(int v, int w, double weight) {
    this.v = v;
    this.w = w;
    this.weight = weight;
}

构造函数接收两个顶点标识和一个权重,初始化边的基本属性。

方法

  • weight():返回边的权重。

    java 复制代码
    public double weight() { return weight; }
  • either():返回边的一个顶点。此方法用于访问边的任一端点,通常在边的迭代中使用。

    java 复制代码
    public int either() { return v; }
  • other(int vertex) :给定边的一个顶点,返回另一个顶点。如果传入的顶点不是这条边的一部分,抛出 IllegalArgumentException

    java 复制代码
    public int other(int vertex) {
        if (vertex == v) return w;
        else if (vertex == w) return v;
        else throw new IllegalArgumentException("Invalid vertex");
    }
  • compareTo(myEdge that):实现 `Comparable接口的方法,用于比较两条边的权重。这使得边可以被排序,通常用于算法如 Kruskal 的最小生成树算法中。

    java 复制代码
    public int compareTo(myEdge that) {
        return Double.compare(this.weight, that.weight);
    }
  • toString() :提供边的字符串表示,格式为 "v-w weight",其中 vw 是顶点标识,weight 是边的权重。这对于打印和调试很有用。

    java 复制代码
    public String toString() {
        return String.format("%d-%d %.2f", v, w, weight);
    }

总结

myEdge 类提供了一个结构化的方式来表示图中的边,包括边的两个端点和权重。实现 Comparable 接口允许边根据权重进行排序,这在很多图算法中非常重要,特别是那些需要考虑边权重的算法,如最小生成树或最短路径算法。通过方法 either()other() ,可以方便地在图的上下文中使用边,而 toString() 方法则提供了边的直观表达,便于输出和调试。

myEdgeWeightedGraph

java 复制代码
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;

public class myEdgeWeightedGraph
{
    private int V;
    private int E;
    private myBag<myEdge>[] adj;
    private static final String NEWLINE = System.getProperty("line.separator");

    public myEdgeWeightedGraph(int V)
    {
        this.V = V;
        this.E = E;
        adj = (myBag<myEdge>[]) new myBag[V];
        for(int v=0;v<V;v++)
            adj[v]=new myBag<myEdge>();
    }
    public myEdgeWeightedGraph(In in)
    {
        this(in.readInt());
        int E = in.readInt();
        for (int i = 0; i < E; i++)
        {
            int v = in.readInt();
            int w = in.readInt();
            double weight = in.readDouble();
            myEdge e = new myEdge(v,w,weight);
            addEdge(e);
        }
    }
    public int V() {return V;}
    public int E() {return E;}
    public void addEdge(myEdge e)
    {
        int v = e.either(),w=e.other(v);
        adj[v].add(e);
        adj[w].add(e);
        E++;
    }
    public Iterable<myEdge> adj(int v)
    {return adj[v];}
    public Iterable<myEdge> edges()
    {
        myBag<myEdge> b = new myBag<myEdge>();
        for(int v=0;v<V;v++)
            for(myEdge e: adj[v])
                if(e.other(v)<v) b.add(e);
        return b;
    }
    public String toString(){
        StringBuilder s = new StringBuilder();
        s.append(V +" vertexes "+ E + " edges " + NEWLINE);
        for(int v = 0; v<V; v++) {
            s.append(v + ": ");
            for(myEdge e:adj(v))
                s.append(e + "  ");
            s.append(NEWLINE);
        }
        return s.toString();
    }
    public static void main(String[] args)
    {
        In in = new In(args[0]);
        myEdgeWeightedGraph G = new myEdgeWeightedGraph(in);
        StdOut.print(G);
    }
}

这段代码定义了一个表示加权无向图的类 myEdgeWeightedGraph。这里的每个重要组成部分我将逐一说明:

  1. 构造函数
    • 第一个构造函数接受一个顶点数 V,初始化图,为每个顶点创建一个用于存储边的链表。
    • 第二个构造函数通过读取一个输入源来构建图。它首先读取顶点数和边数,然后连续读取每条边的两个顶点和权重,并将这些边添加到图中。
  2. 边的添加
    • addEdge 方法用于向图中添加一条边,同时将边添加到两个顶点的邻接链表中。
  3. 图的信息获取
    • V()E() 方法分别返回图的顶点数和边数。
    • adj(int v) 方法返回与顶点 v 相连的所有边。
    • edges() 方法返回图中的所有边,确保每条边只被列出一次。
  4. 图的字符串表示
    • toString 方法生成并返回图的字符串描述,包括每个顶点及其相邻的边。
  5. 主函数
    • main 方法从文件读取图数据,构建图对象,并打印图的字符串表示。

实验

代码编译

bash 复制代码
$ javac myEdge.java
$ javac myEdgeWeightedGraph.java

代码运行

bash 复制代码
$ java myEdgeWeightedGraph ..\data\tinyEWG.txt
8 vertexes 16 edges 
0: 6-0 0.58  0-2 0.26  0-4 0.38  0-7 0.16
1: 1-3 0.29  1-2 0.36  1-7 0.19  1-5 0.32
2: 6-2 0.40  2-7 0.34  1-2 0.36  0-2 0.26  2-3 0.17
3: 3-6 0.52  1-3 0.29  2-3 0.17
4: 6-4 0.93  0-4 0.38  4-7 0.37  4-5 0.35
5: 1-5 0.32  5-7 0.28  4-5 0.35
6: 6-4 0.93  6-0 0.58  3-6 0.52  6-2 0.40
7: 2-7 0.34  1-7 0.19  0-7 0.16  5-7 0.28  4-7 0.37
相关推荐
alphaTao4 分钟前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode
天天扭码7 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶8 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺12 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
kitesxian13 分钟前
Leetcode448. 找到所有数组中消失的数字(HOT100)+Leetcode139. 单词拆分(HOT100)
数据结构·算法·leetcode
小曲程序19 分钟前
vue3 封装request请求
java·前端·typescript·vue
陈王卜37 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、37 分钟前
Spring Boot 注解
java·spring boot
java亮小白199742 分钟前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF1 小时前
java Queue 详解
java·队列