有向网的各种功能实现
有向网的各种功能实现:
1:在邻接矩阵、邻接表和逆邻接表之间转换。
2:完成增加顶点和删除顶点的功能,删除顶点也要删除与之关联的边;
3:完成增加边和删除边的功能;
4:完成图的深度优先遍历和广度优先遍历;
5:广度优先的生成树并对生成树进行遍历
6:判断图的连通性,输出连通分量的个数;
7:判断图中是否存在环;
8:判断u到v是否存在路径;
9:实现Dijkstra和Floyd算法求最短路径;
import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; import java.util.Stack; public class DiNet<AnyType> { class Ver<AnyType>{ //存储顶点 int data; Arc firstArc; boolean visit; boolean known; Ver path; int dist; int inDeg; public Ver(int data){ this.data=data; this.firstArc=null; this.inDeg=0; } public Ver(int dist,int data){ this.dist=dist; this.data=data; } } class Arc<AnyType>{ //存储邻接点 int adjVex; Arc nextArc; int weight; public Arc(int adjVex,int weight){ this.adjVex=adjVex; this.nextArc=null; this.weight=weight; } } class CSNode<AnyType>{ //孩子兄弟表示法 结点定义 int data; CSNode firstChild; CSNode nextSibling; public CSNode(int data){ this.data=data; this.firstChild=null; this.nextSibling=null; } public CSNode(){ this.firstChild=null; this.nextSibling=null; } } Ver vertexts[]; Scanner sc=new Scanner(System.in); int count=0; //连通性标志 Ver begin,end; //判断是否存在环时用到,路径的开始与结尾 boolean flag;//是否存在环的标识符 //创建图 public Ver[] creatNet(){ System.out.println("请输入顶点个数"); int verNumber=sc.nextInt(); System.out.println("请输入要创建的网的边数:"); int edgeNumber=sc.nextInt(); System.out.println("请输入各个节点的数据:"); vertexts=new Ver[verNumber]; for(int i=0;i<verNumber;i++){ //将顶点存入数组中 vertexts[i]=new Ver(sc.nextInt()); } System.out.println("请输入各条边(顶点在数组中的下标)及边的权重:"); for(int i=0;i<edgeNumber;i++){ //输入边的弧头w,弧尾v,权重we, int v=sc.nextInt(); int w=sc.nextInt(); int we=sc.nextInt(); Arc p=new Arc(w,we); p.nextArc=vertexts[v].firstArc; vertexts[v].firstArc=p; vertexts[w].inDeg++; //弧头指向的顶点入度加一 } return vertexts; } //获取第一个邻接点 public int firstArc(int v){ Arc p=vertexts[v].firstArc; if(p==null) return -1; return p.adjVex; } //获取v相对于w的下一个邻接点 public int nextArc(int v,int w){ Arc p=vertexts[v].firstArc; while(p.adjVex!=w){ p=p.nextArc; } if(p.nextArc==null) return -1; return p.nextArc.adjVex; } //DFS public void DFS(int v){ int w; vertexts[v].visit=true; System.out.print(vertexts[v].data+" "); for(w=firstArc(v);w>=0;w=nextArc(v,w)){ if(vertexts[w].visit==false){ DFS(w); } } } public void DFSTravel(){ for(int i=0;i<vertexts.length;i++){ //令所有顶点的visit都为false vertexts[i].visit=false; } System.out.println("深度优先遍历"); for(int v=0;v<vertexts.length;v++){ //对每个没有被访问过的顶点都要进行深度优先遍历 if(vertexts[v].visit==false){ count++; //若count最终大于1,说明网无法从一个顶点开始一次遍历完,即为非连通图 DFS(v); } } System.out.println(); } //BFS public void BFS(){ int w; Queue<Integer> q=new LinkedList<Integer>(); for(int i=0;i<vertexts.length;i++){ //令所有顶点的visit都为false vertexts[i].visit=false; } System.out.println("广度优先遍历"); for(int i=0;i<vertexts.length;i++){ if(vertexts[i].visit==false){ vertexts[i].visit=true; //标记为已访问 System.out.print(vertexts[i].data+" "); q.add(i); //将访问过的顶点入队 while(!q.isEmpty()){ int v=q.remove(); for(w=firstArc(v);w>=0;w=nextArc(v,w)){ //对v的所有邻接点都进行判断是否已访问 if(vertexts[w].visit==false){ System.out.print(vertexts[w].data+" "); vertexts[w].visit=true; q.add(w); } } } } } System.out.println(); } //转换成邻接矩阵 public void matrix(){ int max=999; //初始值为无穷,用一个极大的数代替 int num=vertexts.length; int m[][]=new int[num][num]; //初始化数组,值均为max for(int i=0;i<num;i++){ for(int j=0;j<num;j++){ m[i][j]=max; } } //赋值,将边的权重加入数组中 for(int i=0;i<num;i++){ Arc p=vertexts[i].firstArc; while(p!=null){ m[i][p.adjVex]=p.weight; p=p.nextArc; } } //输出 System.out.println("矩阵表示法如下图:"); for(int i=0;i<num;i++){ System.out.print(" "+vertexts[i].data+" "); } for(int i=0;i<num;i++){ System.out.println(); System.out.print(vertexts[i].data); for(int j=0;j<num;j++){ if(m[i][j]==999){ System.out.print(" * "); } else System.out.print(" "+m[i][j]+" "); } } System.out.println(); } //输出 public void printMatrix(){ matrix(); } //逆 邻接表 public Ver[] inverse(){ int num=vertexts.length; Ver inver[]=new Ver[num]; //定义一个数组存放顶点 for(int i=0;i<num;i++){ //将顶点存入数组 inver[i]=new Ver(vertexts[i].data); } for(int i=0;i<num;i++){ //找到指向vertexts[i]的所有邻接点在数组中的位置,并将i封装到Arc中接到数组后边 Arc p=vertexts[i].firstArc; while(p!=null){ Arc newArc=new Arc(i,p.weight); newArc.nextArc=inver[p.adjVex].firstArc; inver[p.adjVex].firstArc=newArc; } } return inver; } //扩容 public void increaseSpace(int space){ Ver b[]=vertexts; vertexts=new Ver[space]; for(int i=0;i<b.length;i++){ vertexts[i]=b[i]; } } //减小数组长度 public void reduceSpace(int space){ Ver b[]=vertexts; vertexts=new Ver[space]; for(int i=0;i<space;i++){ vertexts[i]=b[i]; } } //增加顶点 public void addPoint(){ System.out.println("请输入要增加的顶点的个数"); int num=sc.nextInt(); int oldSize=vertexts.length; int newSize=oldSize+num; //增加后顶点总数 increaseSpace(newSize); //扩容 System.out.println("请输入要增加的顶点"); for(int i=oldSize;i<newSize;i++){ int p=sc.nextInt(); vertexts[i]=new Ver(p); } System.out.println("添加成功!!!"); } //删除顶点 public void deletePoint(){ System.out.println("请输入要删除的顶点"); int n=sc.nextInt(); if(n>=vertexts.length) System.out.println("要删除的顶点不存在"); else{ for(int i=0;i<vertexts.length;i++){ //删除相关的边(以被删除顶点为弧头的边) Arc p=vertexts[i].firstArc; while(p!=null){ if(p.adjVex==n){ deleteEdge(i,n); break; } p=p.nextArc; } } for(int i=n;i<vertexts.length-1;i++){ //删除顶点 vertexts[i]=vertexts[i+1]; //令被删除顶点后面的所有顶点前移, } reduceSpace(vertexts.length-1); int w; for(int i=0;i<vertexts.length;i++){ //调整顶点的邻接点 Arc p=vertexts[i].firstArc; while(p!=null){ if(p.adjVex>n){ //邻接点的数据大于n,则减1 p.adjVex--; } p=p.nextArc; } } System.out.println("删除成功!!!"); } } //增加边 public void addEdge(){ System.out.println("请输入要增加边"); int v=sc.nextInt(); //弧尾 int w=sc.nextInt(); //弧头 System.out.println("请输入要增加边的权"); int we=sc.nextInt(); Arc p=new Arc(w,we); p.nextArc=vertexts[v].firstArc; vertexts[v].firstArc=p; System.out.println("添加成功!!!"); } //删除边 public void deleteEdge(){ System.out.println("请输入要删除的边"); int v=sc.nextInt(); int w=sc.nextInt(); deleteEdge(v,w); System.out.println("删除成功!!!"); } public void deleteEdge(int v,int w){ Arc p=vertexts[v].firstArc; if(p.adjVex==w){ //是第一个邻接点 vertexts[v].firstArc=p.nextArc; } else{ //不是第一个邻接点 while(p.nextArc.adjVex!=w&&p.nextArc!=null){ p=p.nextArc; } p.nextArc=p.nextArc.nextArc; } } //判断是否为连通图 public void isLianTong(){ DFSTravel(); if(count==1) System.out.println("该图为连通图"); else System.out.println("该图不是连通图,连通分量个数为:"+count); count=0; } //广度优先生成树 public CSNode BFSTree(){ int w; int n=0; //判断是否已近存在一个根 CSNode rootNode=null; Queue<Integer> q=new LinkedList<Integer>(); for(int i=0;i<vertexts.length;i++){ //令所有顶点的visit都为false vertexts[i].visit=false; } CSNode node=new CSNode(); for(int i=0;i<vertexts.length;i++){ if(vertexts[i].visit==false){ //未被访问 vertexts[i].visit=true; if(n==0){ //还没有根,则该点作为根 node=new CSNode(vertexts[i].data); rootNode=node; } if(n!=0){ //已经存在一个根,则该点作为根的兄弟 node.nextSibling=new CSNode(vertexts[i].data); node=node.nextSibling; } q.add(i); while(!q.isEmpty()){ int v=q.remove(); for(w=firstArc(v);w>=0;w=nextArc(v,w)){ if(vertexts[w].visit==false){ if(node.firstChild==null) //第一个孩子 node.firstChild=new CSNode(vertexts[w].data); else{ //第一个孩子的兄弟 CSNode p=node.firstChild; while(p.nextSibling!=null){ p=p.nextSibling; } p.nextSibling=new CSNode(vertexts[w].data); } vertexts[w].visit=true; q.add(w); } } } n++; } } return rootNode; } //层次非递归遍历 public void levelOrder(CSNode root){ int i=0; Queue<CSNode> q=new LinkedList<CSNode>(); q.add(root); while(q.isEmpty()!=true){ CSNode step=q.remove(); System.out.print(step.data); if(step.firstChild!=null){ q.add(step.firstChild); } if(step.nextSibling!=null){ q.add(step.nextSibling); } } System.out.println(); } //判断是否存在环 拓扑排序 public void topSort(){ boolean flag=true; //是否存在环的标志符 Queue<Integer> q=new LinkedList<Integer>(); for(int i=0;i<vertexts.length;i++){ //入度为0的点入队 if(vertexts[i].inDeg==0) q.add(i); } while(!q.isEmpty()){ int w=0; int v=q.poll(); for(w=firstArc(v);w>=0;w=nextArc(v,w)){ vertexts[w].inDeg--; //与v相邻点的入度减1 if(vertexts[w].inDeg==0){ q.add(w); } } } for(int i=0;i<vertexts.length;i++){ //若存在入度不为0的点,则存在环 if(vertexts[i].inDeg>0){ flag=false; break; } } if(flag==false) System.out.println("存在环"); else System.out.println("不存在环"); } //Dijkstra算法 public Ver Dijkstra(){ System.out.println("请输入起始点"); int s=sc.nextInt(); System.out.println("请输入起终点"); int e=sc.nextInt(); for(int i=0;i<vertexts.length;i++){ //初始化,dist为无穷 vertexts[i].known=false; vertexts[i].dist=100; vertexts[i].path=null; } vertexts[s].dist=0; //令起点的dist为0 for(;;){ //找到未知点中dist为最小的顶点v Ver v=new Ver(100,-1); for(int i=0;i<vertexts.length;i++){ if(vertexts[i].dist<v.dist&&vertexts[i].known==false){ v=vertexts[i]; } } if(v.data==-1) //当所有顶点都访问过后退出 break; v.known=true; //对每一个与顶点v邻接的顶点w,依次判断v.dist+cv,w与w.dist的大小,更改w.dist的值 Arc w=v.firstArc; while(w!=null){ if(vertexts[w.adjVex].dist>(v.dist+w.weight)&&vertexts[w.adjVex].known==false){ //w.dist与v.dist+w.weight 比较,确定w.dist vertexts[w.adjVex].dist=v.dist+w.weight; vertexts[w.adjVex].path=v; } w=w.nextArc; } } return vertexts[e]; } public void printpath(Ver v){ if(v.path!=null){ printpath(v.path); System.out.print("to"); } System.out.print(v.data); } //Floyd算法 //核心 public int[][] floyd(){ int num=vertexts.length; int d[][]=new int[num][num]; int e[][]=new int[num][num]; //存放最短路径 int max=999; //定义n阶矩阵D,存储初始两个顶点之间的距离 for(int i=0;i<num;i++){ //初始值为无穷,对角线为0 for(int j=0;j<num;j++){ if(i==j) d[i][j]=0; d[i][j]=max; e[i][j]=0; } } for(int i=0;i<num;i++){ //将路径长加入到d中 Arc p=vertexts[i].firstArc; while(p!=null){ d[i][p.adjVex]=p.weight; p=p.nextArc; } } //由D(k-1)生成新的矩阵D(k),表示任意2个顶点之间最短路径的长度, int k=0,i=0,j=0; for(k=0;k<num;k++) for(i=0;i<num;i++) for(j=0;j<num;j++){ if(d[i][k]+d[k][j]<d[i][j]){ d[i][j]=d[i][k]+d[k][j]; e[i][j]=k; } } for(int a=0;a<num;a++) //令e中没有路径的两顶点为max for(int b=0;b<num;b++){ if(d[a][b]==max&&d[b][a]==max&&e[a][b]==0){ e[a][b]=999; e[b][a]=999; } } return e; } String path=""; //获取路径 public String path(int i,int j,int e[][]){ int k=e[i][j]; if(k==999) return "can't";//不存在路径 if(k==0) return path; path(i,k,e); path+="to"+vertexts[k].data; return path(k,j,e); } public void Floyd(){ System.out.println("请输入顶点和终点"); int begin=sc.nextInt(); int end=sc.nextInt(); System.out.println(vertexts[begin].data+"到"+vertexts[end].data+"的路径为"+vertexts[begin].data+path(begin,end,floyd())+"to"+vertexts[end].data); } //判断是否存在路径 public void isPath(){ System.out.println("请输入两个顶点"); int v=sc.nextInt(); int w=sc.nextInt(); String path=path(v,w,floyd()); if(path.equals("can't")) System.out.println(vertexts[v].data+"和"+vertexts[w].data+"之间不存在路径"); else System.out.println(vertexts[v].data+"和"+vertexts[w].data+"之间存在路径"); } //菜单 public void menu(){ System.out.println("1:创建有向网"); System.out.println("2:增加顶点"); System.out.println("3:删除顶点"); System.out.println("4:增加边"); System.out.println("5:删除边"); System.out.println("6:DFS"); System.out.println("7:BFS"); System.out.println("8:判断是否存在路径"); System.out.println("9:转成邻接矩阵,并输出 "); System.out.println("10:BFS生成树"); System.out.println("11:Dijkstra算法"); System.out.println("12:floyd算法"); System.out.println("13:判断是否存在环"); System.out.println("14:判断是否是连通图"); System.out.println("0:退出"); System.out.println("***********************************"); } public void choice(){ System.out.println("请输入您的要进行的操作:"); } public static void main(String[] args) { DiNet d=new DiNet(); Scanner sc=new Scanner(System.in); d.menu(); boolean flag=true; while(flag){ d.choice(); int c=sc.nextInt(); switch(c){ case 0: flag=false; case 1: d.creatNet(); break; case 2: d.addPoint(); break; case 3: d.deletePoint(); break; case 4: d.addEdge(); break; case 5: d.deleteEdge(); break; case 6: d.DFSTravel(); break; case 7: d.BFS(); break; case 8: d.isPath(); break; case 9: d.matrix(); break; case 10: d.levelOrder(d.BFSTree()); break; case 11: d.printpath(d.Dijkstra()); break; case 12: d.Floyd(); break; case 13: d.topSort(); break; case 14: d.isLianTong(); break; default :System.out.println("您输错了,请重新输入"); } } /*实例: 0 1 2 0 3 1 1 3 3 1 4 10 2 0 4 2 5 5 3 2 2 3 4 2 3 5 8 3 6 4 4 6 6 6 5 1 */ /*0 1 1 1 3 1 3 7 1 4 1 1 4 7 1 0 2 1 2 5 1 2 6 1 5 6 1*/ } }