有向网的各种功能实现:
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*/
}
}