//Edge类, 表示边的信息
public class Edge implements Comparable {
private int a, b; //边的两个节点, 表示边 a->b
private Weight weight; //边的权重,不一定是数字类型
public Edge(int a,int b, Weight weight){
this.a = a;
this.b = b;
this.weight = weight;
}
public Edge(Edge e){
this(e.a, e.b, e.weight);
}
//返回第一个顶点
public int v(){
return this.a;
}
//返回第二个顶点
public int w(){
return this.b;
}
//返回权重
public Weight weight(){
return this.weight;
}
//给定一个顶点返回另一个顶点
public int otherV(int v){
assert v == a || v == b;
return v == a? b:a;
}
//输出边的信息
public String toString(){
return ""+a+"-"+b+":"+weight;
}
//边之间的比较
@Override
public int compareTo(Edge other){
if(weight.compareTo(other.weight())>0){
return 1;
}else if(weight.compareTo(other.weight())<0){
return -1;
}else{
return 0;
}
}
}
//有权稠密图 邻接矩阵表示
public class DenseGraph implements WeightGraph {
private int n; //节点数
private int m; //边数
private boolean isDirected; //是否为有向图
private Edge[][] g; //图的具体数据
public DenseGraph(int n, boolean isDirected){
assert n>=0;
this.n = n;
this.m = 0;
this.isDirected = isDirected;
// g初始化为n*n的矩阵, 每一个g[i][j]均为null, 表示没有任和边
this.g = new Edge[n][n];
for(int i=0; iw 是否存在
@Override
public boolean hasEdge(int v, int w){
assert v >= 0 && v < n ;
assert w >= 0 && w < n ;
return g[v][w] != null;
}
@Override
public void addEdge(Edge e){
assert e.v()>=0 && e.v()=0 && e.w()> adjIterator(int v){
assert v >= 0 && v < n;
Vector> vector = new Vector<>();
for(int i=0; i
//有权稀疏图 邻接表的表示
public class SpraseGraph implements WeightGraph {
private int n; //节点数
private int m; //边数
private boolean isDirected; //是否为有向图
private Vector>[] g; //图的具体数据
public SpraseGraph(int n, boolean isDirected){
assert n>=0;
this.n = n;
this.m = 0;
this.isDirected = isDirected;
this.g = (Vector>[]) new Vector[n];
//初始化数组中的每个Vetor
for(int i=0; i>();
}
}
@Override
public int V(){
return this.n;
}
@Override
public int E(){
return this.m;
}
//检查边 v——>w 是否存在
@Override
public boolean hasEdge(int v, int w){
assert v>=0 && v=0 && w e){
assert e.v()>=0 && e.w()=0 && e.w()> adjIterator(int v){
assert v >= 0 && v < n;
return g[v];
}
@Override
public void show(){
for(int i = 0; i
//lazy-prim算法带权无向图最小生成树
public class LazyPrimMST {
private WeightGraph graph; //用来生成最小生成树的图
private boolean[] isVisited; //标记节点是否被访问
private Vector> mst; //最小生成树中的边
private Number mstWeight; //最小生成树的权重和
private PriorityQueue> pq; //算法的辅助数据结构,用来选出权重最小的边
public LazyPrimMST(WeightGraph graph){
this.graph = graph;
this.isVisited = new boolean[graph.V()];
this.mst = new Vector<>();
this.mstWeight = 0;
this.pq = new PriorityQueue<>(graph.E(), new Comparator>() {
@Override
public int compare(Edge o1, Edge o2) {
return o1.compareTo(o2);
}
});
}
//辅助方法,访问节点,并挑选该节点未被访问过的邻边加入优先队列
private void visit(int v){
//判断传入的节点v是否被访问过
assert !isVisited[v];
//访问节点v
isVisited[v] = true;
for(Edge e: graph.adjIterator(v)){
if(!isVisited[e.otherV(v)]){
pq.add(e);
}
}
}
//最小生成树实现 lazy-prim算法
public void mst(){
//初始化,先访问节点0
visit(0);
//lazy-prim
while(!pq.isEmpty()){
//从优先队列中取得当前队列中权重最小的边
Edge e = pq.remove();
//若边的两个端点均被访问过,则抛弃这条边,在从优先队列中取得下一个权重最小的边
if(isVisited[e.v()] == isVisited[e.w()]){
continue;
}
//若边的另一个端点没有被访问过,则该边为最小生成树中的一条边
mst.add(e);
//顺着这条边接着访问边中那个为被访问过的节点
if(!isVisited[e.v()]){
visit(e.v());
}else{
visit(e.w());
}
}
//计算最小生成树中的权重和
for(int i=0; i> mstEdges(){
return this.mst;
}
// 返回最小生成树的权值
public Number minWeight(){
return this.mstWeight;
}
}
//索引堆(构造时,可根据参数选择最大或者最小), 底层基于数组实现
public class IndexMinHeap {
private boolean isMin; //是否为最小索引堆
private E[] items; //存放具体数据
private int[] indexes; //索引堆的底层数组,数组内存储的是具体数据的索引,保持堆的排序
private int[] reverse; //索引堆中的反向索引 reverse[indexes[i]]=i;
private int size; //堆中数据的个数
private int capacity; //堆的容量
public IndexMinHeap(int capacity, boolean isMin){
this.isMin = isMin;
this.capacity = capacity;
this.size = 0;
this.indexes = new int[capacity];
this.items = (E[])new Comparable[capacity];
this.reverse = new int[capacity];
for(int i=0; i=0 && i0;
E ret = items[indexes[0]];
indexes[0] = indexes[size-1];
reverse[indexes[0]] = 0;
size--;
reverse[indexes[size]] = -1;
shiftDown(0);
return ret;
}
// 从索引堆中取出堆顶元素的索引
public int removeIndex(){
assert size>0;
int ret = indexes[0];
indexes[0] = indexes[size-1];
reverse[indexes[0]] = 0;
size--;
reverse[indexes[size]] = -1;
shiftDown(0);
return ret;
}
// 获取索引堆中的堆顶元素
public E get(){
assert size>0;
return items[indexes[0]];
}
// 获取索引堆中的堆顶元素的索引
public int getIndex(){
assert size>0;
return indexes[0];
}
// 看索引i所在的位置是否存在元素
public boolean contain(int i){
assert i>=0 && i0; j=(j-1)/2){
indexes[j] = indexes[(j-1)/2];
reverse[indexes[j]] = j;
}
}else{
for(j=i; e.compareTo(items[indexes[(j-1)/2]])>0 && j>0; j=(j-1)/2){
indexes[j] = indexes[(j-1)/2];
reverse[indexes[j]] = j;
}
}
indexes[j] = ret;
reverse[indexes[j]] = j;
}
// 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
private void shiftDown(int i){
while (2*i+10){
j = j+1;
}
if(items[indexes[i]].compareTo(items[indexes[j]])>0){
break;
}
}
int temp = indexes[i];
indexes[i] = indexes[j];
reverse[indexes[i]] = i;
indexes[j] = temp;
reverse[indexes[j]] = j;
i = j;
}
}
}
//prim算法 求带权无向图的最小生成树
public class PrimMST {
private WeightGraph graph; //待求最小生成树的图
private Vector> mst; //最小生成树的所有边
private Number mstWeight; //最小生成树的权重和
private boolean[] isVisited; //辅助数据结构,记录节点是否被访问过
private Edge[] edgeTo; //辅助数据结构,记录“横切边”, edgeTo[w] 表示已标记区域中某个节点到未标记节点w的边
private IndexMinHeap imheap; //辅助数据结构,最小索引堆,索引表示节点,对应的数据表示该节点到已标记区域的权重
public PrimMST(WeightGraph graph){
this.graph = graph;
assert( graph.E() >= 1 );
this.imheap = new IndexMinHeap<>(graph.V(), true);
this.isVisited = new boolean[graph.V()];
this.mst = new Vector>();
this.mstWeight = 0;
this.edgeTo = (Edge[]) new Edge[graph.V()];
for(int i=0; i e: graph.adjIterator(v)){
if(!isVisited[e.otherV(v)]){
//判断边 v——otherV(v) 是否被标记为"横切边"
//若未标记过,则进行标记,并加入最小堆
//若标记过,则判断之前标记的“横切边”与当前由节点v发出的“横切边”v——otherV(v)那个更短,更新最小堆
if(edgeTo[e.otherV(v)] == null){
edgeTo[e.otherV(v)] = e;
imheap.add(e.otherV(v), e.weight());
}else if(edgeTo[e.otherV(v)].weight().compareTo(e.weight())>0){
//更新到节点e.otherV(v)的“横切边”
edgeTo[e.otherV(v)] = e;
imheap.set(e.otherV(v), e.weight());
}
}
}
}
//prim算法, 生成最小生成树
public void prim(){
//prim
visit(0);
while (!imheap.isEmpty()){
// 使用最小索引堆找出已经访问的边中权值最小的边
// 最小索引堆中,索引表示节点,索引对应的值表示该节点到已标记区域的权重(距离)
int v = imheap.removeIndex();
//assert( edgeTo[v] != null );
mst.add(edgeTo[v]);
visit(v);
}
// 计算最小生成树的权值
for (int i=0; i> mstEdges(){
return this.mst;
}
//返回最小生成树的权重和
public Number mstWeight(){
return this.mstWeight;
}
}
//并查集
public class UnionFind {
private int[] parent;
private int capacity;
private int[] rank;
public UnionFind(int capacity){
this.capacity = capacity;
this.parent = new int[capacity];
this.rank = new int[capacity];
for(int i=0; i rank[qRoot]){
parent[qRoot] = pRoot;
}else{
parent[pRoot] = qRoot;
rank[qRoot]++;
}
}
}
//kruskal算法
public class KruskalMST {
private WeightGraph graph;
private Vector> mst;
private Number mstWeight;
public KruskalMST(WeightGraph graph){
this.graph = graph;
this.mst = new Vector<>();
this.mstWeight = 0;
}
public void kruskal(){
//利用优先队列对图中各条边按照权重从小到大排序
PriorityQueue> pq = new PriorityQueue<>(graph.E());
for(int i=0; i e: graph.adjIterator(i)){
//防止无向图中,同一条边两次入队
if(e.v()<=e.w()){
pq.add(e);
}
}
}
//利用并查集检查加入一条边之前,该边的两个节点是否已经连接
UnionFind uf = new UnionFind(graph.V());
while(!pq.isEmpty() && mst.size() e = pq.remove();
if(uf.isConnected(e.v(), e.w())){
continue;
}
mst.add(e);
uf.unionElements(e.v(), e.w());
}
//计算最小生成树权重
for(int i=0; i> mstEdges(){
return mst;
}
// 返回最小生成树的权值
public Number mstWeight(){
return mstWeight;
}
}