加权无向图
和无向图不同的是,加权无向图在边中加入了另外一个属性,权重,这个权重可以是这个边的任何属性,比如长度,时间,粗细,颜色等等。正是因为假如了另外一个属性,边的实现就相对复杂了,因此将边抽象为一个类,这个类包括两个节点成员变量和一个权重成员变量,用来模拟边。
加权无向图有何用的呢?有用,比如最短路径问题,因为加了权重属性,就可以表示边的长度了。
java代码
package mypackage;
import java.lang.ref.PhantomReference;
import java.util.Iterator;
//队列类,用链表实现,后面有用
class Queue<T> implements Iterable<T>{
// 节点个数,头节点,尾节点
private int N;
private Node head;
private Node last;
//节点类
public class Node {
public T data;
public Node next;
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
//构造方法,初始化
public Queue() {
this.N = 0;
this.head = new Node(null,null);
this.last = null;
}
//队列长度
public int size(){
return N;
}
//队列是否为空
public boolean isEmpty(){
return N==0;
}
//入队列
public void enqueue(T data){
// 如果队列为空,说明尾节点为空,让新节点为尾节点,头借点指向尾节点
if (isEmpty()){
last=new Node(data,null);
head.next=last;
// 如果队列不为空,让新节点为尾节点,老的尾节点指向新尾节点
}else {
Node oldlast=last;
last=new Node(data,null);
oldlast.next=last;
}
// 最后元素+1
N++;
}
//出队列,注意先入先出,每次出的节点就是head指向的第一个节点,然后让head只想第二个节点即可
// 且注意,如果队列为空,要将last=null
public T dequeue(){
// 如果为空,返回null
if (isEmpty()){
return null;
// 如果不为空,让head只想第二个节点,元素-1,且如果队列为空,要将last=null
}else {
Node oldfirst=head.next;
head.next=oldfirst.next;
N--;
if (isEmpty()){
last=null;
}
// 返回弹出的元素
return oldfirst.data;
}
}
// 遍历
@Override
public Iterator iterator() {
return new QIterator();
}
// 创建一个内部类实现Iterator接口
public class QIterator implements Iterator {
// 定义一个遍历的节点
private Node n;
public QIterator() {
// 初始化为0索引位置
this.n = head;
}
//重写两个方法
@Override
public boolean hasNext() {
// 这个方法判断是否超出最大索引,如果超出会停止遍历
return n.next != null;
}
@Override
public Object next() {
// 这个方法会遍历得每个节点
n = n.next;
return n.data;
}
}
}
//边类,因为加权无向图的边比较麻烦,因此专门用一个类表示边
class Edge implements Comparable<Edge>{
//两个顶点,一个权重
private int v;
private int w;
private double weigth;
public Edge(int v, int w, double weigth) {
this.v = v;
this.w = w;
this.weigth = weigth;
}
//获取边的权重值
public double getWeigth(){
return weigth;
}
//获取边一个点
public int either(){
return v;
}
//获取边另一个点
public int other(int x){
if (x==v){
return w;
}else {
return v;
}
}
//重写compareTo方法,提供比较规则,以weigth比较边的大小
@Override
public int compareTo(Edge o) {
int cmp;
if (this.weigth>o.weigth){
cmp= 1;
}else if (this.weigth==o.weigth){
cmp= 0;
}else {
cmp= -1;
}
return cmp;
}
}
//加权无向图,注意边是单独的一个类实现的
class WeigthGraph{
private int V;//顶点数
private int E;//边数
//adj是一个数组,数组的类型的队列,队列里面装的数据类型是Edge边类
private Queue<Edge>[] adj;//邻接表,注意索引是每个顶点
//构造方法,传入顶点个数,初始化边数为0,
public WeigthGraph(int v) {
this.V = v;
this.E=0;
this.adj=new Queue[v];//初始化队列数组,大小为顶点的个数
for (int i = 0; i <adj.length ; i++) {
adj[i]=new Queue<Edge>();//初始化数组的每个队列
}
}
//获得顶点的个数
public int getV(){
return V;
}
//添加边,注意这里的边是单独的类实现的,传入一个边参数,让这个边在两个顶点的邻接表中
//真正的边是需要实现类的
public void addEdge(Edge edge){
int v=edge.either();
int w=edge.other(v);
adj[v].enqueue(edge);
adj[w].enqueue(edge);
E++;//边数+1
}
// 获取边的个数
public int getE(){
return E;
}
//获取某个顶点相邻的所有边,返回这个队列即可
public Queue<Edge> getAdj(int v){
return adj[v];
}
//获取图的所有边
public Queue<Edge> getEdges(){
Queue<Edge> allEdges=new Queue<>();//用来装边
for (int v = 0; v <V ; v++) {
for (Edge e:adj[v]) {
//因为边是无向的,因此如果简单的暴力遍历,就会重复提取边
//因此在将边入栈前判断一下,只有当右顶点大于左顶点是才入栈,这样就不会重复。
if (e.other(v)>v){
allEdges.enqueue(e);
}
}
}
return allEdges;
}
}
//测试
public class MyJava {
public static void main(String[] args){
WeigthGraph weigthGraph=new WeigthGraph(6);
//添加边
weigthGraph.addEdge(new Edge(0,1,10));
weigthGraph.addEdge(new Edge(1,2,15));
weigthGraph.addEdge(new Edge(2,3,20));
weigthGraph.addEdge(new Edge(0,4,10));
weigthGraph.addEdge(new Edge(0,5,100));
System.out.println("顶点数量:"+weigthGraph.getV());
System.out.println("边的条数:"+weigthGraph.getE());
System.out.println("0相邻的顶点:");
for (Edge x:weigthGraph.getAdj(0)){
System.out.print(x.other(0)+"--");
}
System.out.println();
System.out.println("所有边(左顶点+右顶点+长度):");
for (Edge x:weigthGraph.getEdges()){
System.out.print(x.either()+"--"+x.other(x.either())+"--"+x.getWeigth()+" | ");
}
}
}