有向网的各种功能实现

有向网的各种功能实现:

1:在邻接矩阵、邻接表和逆邻接表之间转换。

2:完成增加顶点和删除顶点的功能,删除顶点也要删除与之关联的边;

3:完成增加边和删除边的功能;

4:完成图的深度优先遍历和广度优先遍历;

5:广度优先的生成树并对生成树进行遍历

6:判断图的连通性,输出连通分量的个数;

7:判断图中是否存在环;

8:判断uv是否存在路径;

9:实现DijkstraFloyd算法求最短路径;

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*/
	
	}

}


 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2013-12-28 21:15  dingxiaoyue  阅读(362)  评论(0编辑  收藏  举报