博客初感言:
我的第一篇博客,好激动啊,以前只是经常看别的大侠的博客,还从来没想过自己写,以前我记知识点或学习笔记都是直接写在本子上的,感觉这样看起来更方便,不过还是想尝试一下,分享自己的学习经验。希望自己能坚持下去!
计算稀疏图连通分量
我写了实现稠密图和稀疏图的两个类,目前只写了计算稀疏图连通分量的算法,代码如下:
//稠密图--邻接矩阵
public class DenseGraph{
private int n,m; //顶点,边
private boolean isdirected; //是否有向图
private ArrayList<ArrayList<Boolean>> g=new ArrayList<ArrayList<Boolean>>(); //二维矩阵
public DenseGraph(int n, boolean isdirected) {
this.n = n;
this.m=0; //边
this.isdirected = isdirected;
for(int i=0;i<n;i++){
ArrayList<Boolean> arr=new ArrayList<Boolean>(n);
for(int j=0;j<n;j++)
arr.add(false);
g.add(arr);
}
}
public int V(){return n;}
public int E(){return m;}
//添加边
public void addEdge(int v,int w){
assert(v>=0&&v<n);
assert(w>=0&&w<n);
if(hasEdge(v,w)) //防止有边情况下再m++,所以先判断下
return;
ArrayList<Boolean> arr=g.get(v);
arr.set(w, true);
if(!isdirected){ //若不是有向图
ArrayList<Boolean> sarr=g.get(w);
sarr.set(v, true);
}
m++;
}
public ArrayList<Boolean> getGraph(int n){
return g.get(n);
}
public boolean hasEdge(int v,int w){
assert(v>=0&&v<n);
assert(w>=0&&w<n);
ArrayList<Boolean> arr=g.get(v);
boolean a=arr.get(w);
return a;
}
public static void main(String[] args) {
int N=20; //顶点
int M=100; //边
DenseGraph sg=new DenseGraph(N,false);
for(int i=0;i<M;i++){
sg.addEdge(new Random().nextInt(20), new Random().nextInt(20));
}
System.out.print(" ");
for(int i=0;i<N;i++){
String s=i>=10?(" "+i):(" "+i);
System.out.print(s);
}
System.out.println();
for(int i=0;i<N;i++){
System.out.print(i+" ");
ArrayList<Boolean> srr=sg.getGraph(i);
Iterator<Boolean> ite=srr.iterator();
if(i<10)
System.out.print(" ");
while(ite.hasNext())
System.out.print(" "+(ite.next()?1:0)+" ");
System.out.println();
}
}
}
//稀疏图---邻接表
public class SparseGraph{
private int n,m; //顶点,边
private boolean isdirected; //是否有向图
private ArrayList<ArrayList<Integer>> g=new ArrayList<ArrayList<Integer>>(); //邻接表
public SparseGraph(int n, boolean isdirected) {
this.n = n;
this.m=0;
this.isdirected = isdirected;
for(int i=0;i<n;i++){
ArrayList<Integer> arr=new ArrayList<Integer>();
g.add(arr);
}
}
public int V(){return n;}
public int E(){return m;}
public ArrayList<Integer> getGraph(int n){
return g.get(n);
}
public void addEdge(int v,int w){
assert(v>=0&&v<n);
assert(w>=0&&w<n);
if(hasEdge(v,w)) //排除平行边
return;
if(v!=w){
ArrayList<Integer> arr=g.get(v);
arr.add(w);
m++;
}
if(v!=w&&!isdirected){ //且是无向图
ArrayList<Integer> srr=g.get(w);
srr.add(v);
}
}
public boolean hasEdge(int v,int w){
assert(v>=0&&v<n);
assert(w>=0&&w<n);
ArrayList<Integer> arr=g.get(v);
for(int i=0;i<arr.size();i++){
if(arr.get(i)==w)
return true;
}
return false;
}
public static void main(String[] args) {
int N=30; //顶点
int M=50; //边
SparseGraph sg=new SparseGraph(N,false);
for(int i=0;i<M;i++){
sg.addEdge(new Random().nextInt(N), new Random().nextInt(N));
}
for(int i=0;i<N;i++){
System.out.print(i+" :");
ArrayList<Integer> srr=sg.getGraph(i);
Iterator<Integer> ite=srr.iterator();
while(ite.hasNext())
System.out.print(ite.next()+" ");
System.out.println();
}
Component c=new Component(sg);
System.out.println("该图的连通分量: "+c.count());
}
}
Component类:
//利用深度优先遍历求图的连通分量
public class Component{
private SparseGraph G; //图
private boolean[] visited; //记录每个节点是否被访问过
private int ccount; //记录该图有多少个连通分量
private void dfs(int v){
visited[v]=true;
ArrayList<Integer> arr= G.getGraph(v);
Iterator<Integer> ite=arr.iterator();
while(ite.hasNext()){
int next=ite.next();
if(!visited[next])
dfs(next);
}
}
public Component(SparseGraph g) {
G = g;
visited=new boolean[G.V()];
ccount=0;
for(int i=0;i<G.V();i++){
visited[i]=false;
}
for(int i=0;i<G.V();i++){
if(!visited[i]){
dfs(i);
++ccount;
}
}
}
public int count(){
return ccount;
}
}
我利用的是深度优先遍历算法求稀疏图的连通分量
类Path:通过深度优先遍历来获得路径
public class Path {
private SparseGraph sg;
private int s; //起点
private boolean[] visited;
private int[] from;
//通过深度优先遍历来获得路径
private void dfs(int v){
visited[v]=true;
ArrayList<Integer> arr= sg.getGraph(v);
Iterator<Integer> ite=arr.iterator();
while(ite.hasNext()){
int next=ite.next();
if(!visited[next]){
from[next]=v; //next是从v遍历过来的
dfs(next);
}
}
}
public Path(SparseGraph sg, int s) {
assert(s>=0&&s<sg.V());
this.sg = sg;
this.s = s;
visited=new boolean[sg.V()];
from=new int[sg.V()];
for(int i=0;i<sg.V();i++){
visited[i]=false;
from[i]=-1;
}
//寻路算法
dfs(s);
}
//s到w连不连通
public boolean hasPath(int w){ //终点w
assert(w>=0&&w<sg.V());
return visited[w];
}
//将路径存入arr中
public void path(int w,ArrayList<Integer> arr){
Stack<Integer> s =new Stack<Integer>();
int p=w;
while(p!=-1){
s.push(p);
p=from[p];
}
arr.clear();
while(!s.isEmpty()){
arr.add(s.peek());
s.pop();
}
}
public void showPath(int w){
ArrayList<Integer> arr =new ArrayList<Integer>();
path(w,arr);
for(int i=0;i<arr.size();i++){
System.out.print(arr.get(i));
if(i!=arr.size()-1){
System.out.print("->");
}
}
}
}
类ShortestPath:通过广度优先遍历(层序遍历)求出无权图的最短路径
//通过广度优先遍历(层序遍历)求出无权图的最短路径
public class ShortestPath {
private SparseGraph sg;
private int s; //起点
private boolean[] visited;
private int[] from;
private int[] ord; //记录起点s到每一个节点的最短路径
public ShortestPath(SparseGraph sg, int s) {
assert(s>=0&&s<sg.V());
this.sg = sg;
this.s = s;
visited=new boolean[sg.V()];
from=new int[sg.V()];
ord=new int[sg.V()];
for(int i=0;i<sg.V();i++){
visited[i]=false;
from[i]=-1;
ord[i]=-1;
}
Queue<Integer> q=new LinkedList<Integer>(); //通过LinkedList来实现队列
//无权图最短路径算法
q.offer(s);
visited[s]=true;
ord[s]=0;
while(!q.isEmpty()){
int v=q.peek();
q.poll();
ArrayList<Integer> arr=sg.getGraph(v);
Iterator<Integer> ite=arr.iterator();
while(ite.hasNext()){
int next=ite.next();
if(!visited[next]){
q.offer(next);
visited[next]=true;
from[next]=v;
ord[next]=ord[v]+1;
}
}
}
}
//s到w连不连通
public boolean hasPath(int w){ //终点w
assert(w>=0&&w<sg.V());
return visited[w];
}
//将路径存入arr中
public void path(int w,ArrayList<Integer> arr){
Stack<Integer> s =new Stack<Integer>();
int p=w;
while(p!=-1){
s.push(p);
p=from[p];
}
arr.clear();
while(!s.isEmpty()){
arr.add(s.peek());
s.pop();
}
}
public void showPath(int w){
ArrayList<Integer> arr =new ArrayList<Integer>();
path(w,arr);
for(int i=0;i<arr.size();i++){
System.out.print(arr.get(i));
if(i!=arr.size()-1){
System.out.print("->");
}
}
}
//起点s到终点w的最短路径长度是多少
public int length(int w){
assert(w>=0&&w<sg.V());
return ord[w];
}
}
修改后的main方法
public static void main(String[] args) {
int N=30; //顶点
int M=50; //边
SparseGraph sg=new SparseGraph(N,false);
for(int i=0;i<M;i++){
sg.addEdge(new Random().nextInt(N), new Random().nextInt(N));
}
for(int i=0;i<N;i++){
System.out.print(i+" :");
ArrayList<Integer> srr=sg.getGraph(i);
Iterator<Integer> ite=srr.iterator();
while(ite.hasNext())
System.out.print(ite.next()+" ");
System.out.println();
}
Component c=new Component(sg);
System.out.println("该图的连通分量: "+c.count());
int start=4;
int end=27;
Path p=new Path(sg,start);
ShortestPath sp=new ShortestPath(sg,start);
if(p.hasPath(end)){
System.out.println("从"+start+"到"+end+"的路径为");
p.showPath(end);
}
System.out.println();
if(sp.hasPath(end)){
System.out.println("从"+start+"到"+end+"的最短路径为");
sp.showPath(end);
}
}