加权无向图
加权无向图是一种为每条边关联一个权重值或是成本的图模型。这种图能够自然地表示许多应用。在一副航空图中,边表示航线,权值则可以表示距离或是费用。在一副电路图中,边表示导线,权值则可能表示导线的长度即成本,或是信号通过这条先所需的时间。此时我们很容易就能想到,最小成本的问题,例如,从西安飞纽约,怎样飞才能使时间成本最低或者是金钱成本最低?
在下图中,从顶点0到顶点4有三条路径,分别为0-2-3-4,0-2-4,0-5-3-4,那我们如果要通过那条路径到达4顶点最好呢?此时就要考虑,那条路径的成本最低。
1. 加权无向图边的表示
加权无向图中的边我们就不能简单的使用v-w两个顶点表示了,而必须要给边关联一个权重值,因此我们可以使用对象来描述一条边。
API设计:
类名 | Edge implements Comparable |
---|---|
构造方法 | Edge(int v,int w,double weight):通过顶点v和w,以及权重weight值构造一个边对象 |
成员方法 | 1.public double weight():获取边的权重值 2.public int either():获取边上的一个点 3.public int other(int vertex)):获取边上除了顶点vertex外的另外一个顶点 4.public int compareTo(Edge that):比较当前边和参数that边的权重,如果当前边权重大,返回1,如果一样大,返回0,如果当前权重小,返回-1 |
成员变量 | 1.private fifinal int v:顶点一 2.private fifinal int w:顶点二 3.private fifinal double weight:当前边的权重 |
代码:
/**
* 加权无向图的边
*/
public class Edge implements Comparable<Edge> {
// 顶点一
private final int v;
// 顶点二
private final int w;
// 当前边的权重
private final double weight;
// 通过顶点v和w,以及权重weight值构造一个边对象
public Edge(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;
}
// 获取边上除了顶点vertex外的另外一个顶点
public int other(int vertex) {
if (vertex == v) {
// 如果传入的vertex是v,则返回另一个顶点w
return w;
} else {
// 如果传入的vertex是w,则返回另一个顶点v
return v;
}
}
@Override
public int compareTo(Edge o) {
int cmp = 0;
if (this.weight() > o.weight()) {
// 当前边权重>o边的权重,返回1
cmp = 1;
}
if (this.weight() == o.weight()) {
// 当前边权重=o边的权重,返回0
cmp = 0;
}
if (this.weight() < o.weight()) {
// 当前边权重<o边的权重,返回0
cmp = -1;
}
return cmp;
}
}
2.加权无向图的实现
在无向图的基础上,我们只需要把边的表示切换成Edge对象即可。
API设计:
类名 | EdgeWeightedGraph |
---|---|
构造方法 | EdgeWeightedGraph(int V):创建一个含有V个顶点的空加权无向图 |
成员方法 | 1.public int V():获取图中顶点的数量 2.public int E():获取图中边的数量 3.public void addEdge(Edge e):向加权无向图中添加一条边e 4.public Queue adj(int v):获取和顶点v关联的所有边 5.public Queue edges():获取加权无向图的所有边 |
成员变量 | 1.private fifinal int V: 记录顶点数量 2.private int E: 记录边数量 3.private Queue[] adj: 邻接表 |
代码:
/**
* 加权无向图
*/
public class EdgeWeightedGraph {
// 记录顶点数量
private final int V;
// 记录边数量
private int E;
// 邻接表
private Queue<Edge>[] adj;
// 创建一个含有V个顶点的空加权无向图
public EdgeWeightedGraph(int v) {
// 初始化顶点数量
this.V = v;
// 初始化边数量
this.E = 0;
// 初始化邻接表
this.adj = new Queue[V];
// 初始化邻接表中的空队列
for (int i = 0; i < v; i++) {
adj[i] = new Queue<Edge>();
}
}
// 获取图中顶点的数量
public int V() {
return V;
}
// 获取图中边的数量
public int E() {
return E;
}
// 向加权无向图中添加一条边e
public void addEdge(Edge e) {
// 获取边的一个顶点
int v = e.either();
// 获取边的另一个顶点
int w = e.other(v);
// 无向图,两个顶点都要记录边
adj[v].enqueue(e);
adj[w].enqueue(e);
// 边的数量+1
E++;
}
// 获取和顶点v关联的所有边
public Queue<Edge> adj(int v) {
return adj[v];
}
// 获取加权无向图的所有边
public Queue<Edge> edges() {
// 创建一个队列,存储所有的边
Queue<Edge> allEdge = new Queue<>();
// 遍历每个顶点,拿到其对应的邻接表
for (int v = 0; v < V; v++) {
// 遍历邻接表中的边,添加到队列中
for (Edge e : adj[v]) {
/*
无向图的边在邻接表中会重复存储,v的邻接表存储边e,w的邻接表也存储边e
但是每条边相连的两个顶点是v<w的,
所以只要判断边相连的两个顶点是v<w,再将边入队列,就会去掉重复的边
*/
if (v < e.other(v)) {
allEdge.enqueue(e);
}
}
}
return allEdge;
}
}