学到无向图了,有点难度但是能克服。代码看的很慢,但是不方,任何人想变成大神都不可能一蹴而就,都是经过不懈的努力,一点一点积累起来的。所以,加油啦!
手写了一遍无向图的相关内容,为了方便复习,注释写的很详细。记录在此。
无向图Graph基类
import java.util.Arrays;
/**
* Created by eminem on 16-12-5.
*/
//p336 Graph数据类型
/***图文件的第一行的数字是图中数的范围
* 图文件的第二行的数字是图文件中的数字的对数,也是边数
***/
public class Graph {
//顶点数目 vertices
private final int V;
//边数目 Edge
private int E;
//邻接表
private Bag<Integer>[] adj;
//这个构造函数用来创建邻接表
public Graph(int V) {
this.V = V;
adj = (Bag<Integer>[]) new Bag[V];
//Arrays.fill(adj, new Bag<Integer>());
for (int i = 0; i < V; i++) {
adj[i] = new Bag<Integer>();
}
}
//这个构造函数用来读取图,并向邻接表内存储数据
public Graph(In in) {
this(in.readInt());
E = in.readInt();
for (int i = 0; i < E; i++) {
//添加一条边
int v = in.readInt();
int w = in.readInt();
addEdge(v, w);
}
}
public int V() {
return V;
}
public int E() {
return E;
}
public void addEdge(int v, int w) {
adj[v].add(w);
adj[w].add(v);
//E++;
}
//adj返回的是数组的一个元素,这个元素的索引v是图的某个顶点。
// 而这个元素本身是一个Bag类型,Bag里面存放了和这个节点相邻的那些顶点
//即adj返回的是某顶点v的相邻顶点
public Iterable<Integer> adj(int v) {
return adj[v];
}
//最后的结果类似于 1:2 3 "\n" 4:5 6"\n"7:8 9"\n"10: 11 12
public String toString() {
String s = V + "vertices," + E + "edges\n";
for (int v = 0; v < V; v++) {
s += v + ":";
for (int w : this.adj(v)) {
s += w + " ";
}
s += "\n";
}
return s;
}
}
无向图的常用操作工具:
/**
* Created by eminem on 16-12-5.
*/
public class GraphHandle {
public static int degree(Graph G,int v){
int degree=0;
for(int fuck:G.adj(v)){
degree++;
}
return degree;
}
public static int maxDegree(Graph G){
int max=0;
int V=G.V();
for (int i = 0; i <V ; i++) {
int fuck=degree(G,V);
if(fuck>max){
max=fuck;
}
}
return max;
}
public static double avgDegree(Graph G){
return 2.0*G.E()/G.V();
}
//检查自环
public static int numberOfSelfLoop(Graph G){
int count=0;
for(int v=0;v<G.V();v++){
//迭代和v(v是小于范围V的数字,它是图的顶点)相邻的每一个顶点fuck
for(int fuck:G.adj(v)){
//如果发现fuck和v相等
if(fuck==v){
count++;
}
}
}
return count/2;
}
}
无向图的深度优先搜索:
import java.util.*;
/**
* Created by eminem on 16-12-6.
*/
public class DepthFirstSearch {
//这个顶点调用过dfs()了吗
private boolean[] marked;
//从起点到一个顶点的已知路径上的最后一个顶点
private int[] edgeTo;
//起点
private final int s;
public DepthFirstSearch(Graph G, int s) {
marked = new boolean[G.V()];
edgeTo = new int[G.V()];
this.s = s;
dfs(G, s);
}
/**
* 函数功能:
* 修改marked[],使marked可以被用来判断某顶点是否被访问过
* 修改edgeTo[],使其记录连接某顶点的“上一个”顶点
**/
private void dfs(Graph G, int v) {
marked[v] = true;
//G.adj(v)返回的是和v连通的所有顶点的一个迭代器
for (int w : G.adj(v)) {
//对于每一个w,凡是被访问过的,marked[w]都为true
//如果没有标记,说明还未被访问,就会去执行if()内的内容
if (!marked[w]) {
//如果已经访问过了,比如a-v,v第一次被a访问,edgeTo[v]==a,那么c-v时则不会执行if里的内容,不会执行edgeTo[v]=c
//若还没有被访问,那么这次就要访问了
// 则edgeTo[w]被写入从起点到该顶点w已知路径的最后一条边 s...w-v,用v来表示
edgeTo[w] = v;
//递归地去处理w这个顶点,因为也有一些顶点和w连接,adj(w)同样会返回和w连接的顶点的迭代器
dfs(G, w);
}
}
}
public boolean hasPathTo(int v) {
//只要被访问过,就说明对于顶点v来说有路径通向起点s
return marked[v];
}
//返回起点s到v的路径,s已经在初始化DepthFirstSearch时指定了
public Iterable<Integer> pathTo(int v) {
//若没有路径通向起点s,则返回null
if (!hasPathTo(v)) {
return null;
}
Stack<Integer> fuck = new Stack<Integer>();
//从某顶点v开始向前访问,没访问一次就改变x的值,并把压入栈中
// 直到访问到顶点s为止
for (int x = v; x != s; x = edgeTo[x]) {
fuck.push(x);
}
//最后把顶点s压入栈中
fuck.push(s);
return fuck;
}
}