图的存储方式(Leetcode743为例)

对于n个节点、m条边的图,一般有三种存储方式:邻接矩阵、邻接表和类。

1. 邻接矩阵

定义n×n的二维矩阵,graph[i][j]=w,表示从节点i到节点j有一条权重为w的边。

无向图的邻接矩阵是对角阵,无权图的邻接矩阵数值为0或1,表示是否连通。

邻接矩阵适用于边数较多的稠密图,边数接近点数的平方,m≈n^2。

int[][] graph = new int[n][n];
for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        graph[i][j] = i == j ? 0 : Integer.MAX_VALUE;
    }
}

// 存储
for (int[] time : times) {
    graph[time[0]][time[1]] = time[2];
}

// 遍历以k为起点的所有边
for (int i = 0; i < n; i++) {
    System.out.println(graph[k][i])
}

// 遍历以k为终点的所有边
for (int i = 0; i < n; i++) {
    System.out.println(graph[i][k])
}

2. 邻接表

又称链式前向星存图,定义n个链表存储各节点对应的边集合、长度为n的数组存储链表的头节点,通常使用数组模拟单链表(头插法)。

邻接矩阵适用于边数较少的稀疏图,边数接近点数,m≈n。

int[] graph = new int[n];    // 节点对应边集合的头结点
int[] edges = new int[m];    // 边的链表关系,用于找到下一条边
int[] tails = new int[m];    // 边的终点
int[] weights = new int[m];  // 边的权重
Arrays.fill(graph, -1);
Arrays.fill(edges, -1);

// 存储
for (int i = 0; i < m; i++) {
    int a = times[i][0];
    int b = times[i][1];
    int w = times[i][2];
    edges[i] = graph[a];       // 边i指向起点链表的当前头结点
    graph[a] = i;              // 起点链表的头结点更新为i
    tails[i] = times[i][1];    // 终点
    weights[i] = times[i][2];  // 权重
}

// 遍历以k为起点的所有边
for (int i = graph[k]; i!=-1; i = edges[i]) {
    System.out.println(tails[i]);
    System.out.println(weights[i]);
}

3. 类

创建Edge类记录边信息(起点、终点和权重),等同于使用二维数组edges[m][3]存储边信息,是最简单的存储方式。

通常只有需要确保某种操作复杂度严格O(m)时,才会考虑使用。

class Edge {
    int a;
    int b;
    int w;
    
    public Edge(int a, int b, int w) {
        this.a = a;
        this.b = b;
        this.w = w;
    }
}

List<Edge> edges = new ArrayList<>();

参考文献

修订记录

日期版本号作者修订内容备注
2020-08-251.0moonspiritacm创建文档
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值