# 快速看懂链式向前星(JAVA实现)构建图
Posted tacit-lxs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# 快速看懂链式向前星(JAVA实现)构建图相关的知识,希望对你有一定的参考价值。
快速看懂链式向前星(JAVA实现)
1.概念
它是一种存储图数据的一种方法,使用它可以轻易完成图的构建。相比于邻接矩阵更容易实现,只是不如邻接矩阵灵活。它和邻接表类似,只不过它是用的头插法,每个点形成的链条顺序和邻接表相反。
-
它由边集数组edges[]和头结点head[]数组构成
edges[i]表示数组中存放的第 i 条边,head[i]表示以i为起点的第一条边的下标,比如2这个点,以他为起点有两条边,假设边输入顺序为1->2(第0条边)、2->3(第1条边)、2->4(第2条边)。 那么head[2] = 2,以2为起点的第一条边在数组edges中的下标为2。
边集数组
更具体的,如上面这张有向带权图(对于无向图可以看作两个结点之间有正向和反向的有向图),我们知道每个结点的编号1、2、3、4,以及每一条边的权重。
首先给每一条边编号(从0开始),这里假设1->2为第0条边,2->3为第1条边,2->4为第2条边。
结点信息用一个类表示
// 建立边集
public static class Edge
int to;
int w;
int next;
这样访问第i条边的去向即为:edges[i].to,访问第i条边的权重即为edges[i].w
头结点
你肯定在疑惑next表示什么,并且会为怎么访问一个点的邻接点、遍历这个图而困惑,next就是answer。
首先得从添加每一条边的方式讲起。
public static void add(int u,int v,int w)
edges[cnt] = new Edge();//创建一条边将其放入边集数组
edges[cnt].to = v;
edges[cnt].w = w;
edges[cnt].next = head[u];
head[u] = cnt++;
其中cnt是一个全局变量,初始化为0,表示每一条边的下标。
然后就是我们的主角head头结点数组
head = new int[node_num + 1];//这里结点数加1,是因为结点编号从1开始的。
for (int i = 0; i < head.length; i++)
head[i] = -1;
现在开始整个构建过程
-
add(1,2,3)加载第一条边。
在调用这个方法是,cnt = 0;所以edges[0].to = 2(表示结点1去往结点2), edges[0].w = 3(表示第0条边的权重为3)。
下面是重点,edges[0].next = head[1] = -1(表示以节点1为起点的下一条边的位置,因为结点1为起点的只有一条边,所以-1就代表它没有下一条边了)。
最后,head[1] = cnt++, 这里表示head[1] = 0, cnt = 1;
结果如图:
-
add(2,3,4)
重复上面的流程,得到
-
add(2,3,5)
继续重复得到:
到此建图完毕,我们可以根据head数组,得到每条边在edges数组中的位置,然后访问edges数组得到每一条边的信息。
比如,head[2] = 2, 说明以2为起点第一条边在edges数组中的下标为2,说明这是第2条边,然后根据下标就可以访问edges数组,得到对应边的信息。从上图看出deges[2].next 为1,表示以2为起点的下一条边的下标为1,再得到其信息,这样就可以遍历以2为起点的所有边。当我们依次从每个结点这样访问一边,就遍历了整个图。
特别的
对于无向图,我们可以用异或操作轻松的获取一条边的反向边。
比如有0,1,2,3,4,5条边,0和1互为反向边,3和4互为反向边,4和5互为反向边。那么 当我们想知道第i条边的反向边是那条边时,就可用 i异或1得到。具体的,4^1 = 5 ,5^1 = 4
public static void bfs(int node_num)
// 标记数组,用于标记没有访问过的结点
boolean[] visited = new boolean[node_num+1];
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
while (!queue.isEmpty())
int u = queue.poll();
System.out.print(u+" ");
// 从某个点开始,访问这个点出发的所有边
for (int i = head[u]; i != -1; i = edges[i].next)
int f = edges[i].to;
if (!visited[f])
queue.offer(f);
visited[f] = true;
2.代码
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class ChainForwardStar
private static Edge[] edges ;//边集数组,存放所有的边
private static int cnt = 0; //记录边的下标,比如,如果边的编号从零开始,那么第1条边的下标就是0
private static int[] head;//头结点数组,
// 建立边集
public static class Edge
int to;
int w;
int next;
public static void main(String[] args)
Scanner scanner = new Scanner(System.in);
System.out.println("请输入节点个数:");
int node_num = scanner.nextInt();
head = new int[node_num + 1];
for (int i = 0; i < head.length; i++)
head[i] = -1;
System.out.println("请输入边的数量:");
int edge_num = scanner.nextInt();
edges = new Edge[edge_num];
// scanner.nextLine();
System.out.println("请输入所有边,及他们的权重:");
// 建图
for (int i = 0; i < edge_num; i++)
// String str = scanner.nextLine();
// String[] split = str.split(" ");
// int u = Integer.valueOf(split[0]);
// int v = Integer.valueOf(split[0]);
// int w = Integer.valueOf(split[0]);
int u = scanner.nextInt();
int v = scanner.nextInt();
int w = scanner.nextInt();
add(u,v,w);
// 遍历某个节点的邻接点
System.out.println("请输入想要遍历的结点:");
int node = scanner.nextInt();
for (int u = head[node]; u != -1; u = edges[u].next)
System.out.println("第"+u+"条边的去往结点-》"+ edges[u].to);
System.out.println("第"+u+"条边的的权重" + edges[u].w);
if (u == -1)
break;
System.out.println(node + "号结点上出发的下一条边的下标:"+edges[u].next);
// 输出访问结点的顺序
bfs(node_num);
public static void add(int u,int v,int w)
edges[cnt] = new Edge();//创建一条边将其放入边集数组
edges[cnt].to = v;
edges[cnt].w = w;
edges[cnt].next = head[u];
head[u] = cnt++;
public static void bfs(int node_num)
boolean[] visited = new boolean[node_num+1];
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
while (!queue.isEmpty())
int u = queue.poll();
System.out.print(u+" ");
for (int i = head[u]; i != -1; i = edges[i].next)
int f = edges[i].to;
if (!visited[f])
queue.offer(f);
visited[f] = true;
3. 结果
以上是关于# 快速看懂链式向前星(JAVA实现)构建图的主要内容,如果未能解决你的问题,请参考以下文章