使用邻接表表示图(无向无权图)

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Scanner;

public class AdjList 
{
	
	private int V;//顶点
	private int E;//边
	private LinkedList<Integer> [] adj;//邻接表
	
	public AdjList(String filename) 
	{//从文件中读取图的信息,并构建一个无向图
		
		File file=new File(filename);
		
		try(Scanner scanner=new Scanner(file))
		{//这样写不用考虑回收资源
			
			V=scanner.nextInt();//读取图的顶点数
			
			if(V<0)
			{//由于一个图最少有一个顶点,于是要考虑到方方面面的情况
				throw new IllegalArgumentException("V must be non-negative");
			}
			
			adj=new LinkedList[V];//使用读取进来的第一行的数字创建一个邻接表
			//由于java语法的特点邻接表的创建只能使用这种形式
			//先进行链表的创建,在进行对链表中每一个节点进行空间申请的操作
			
			for(int i=0;i<V;i++)
			{//对链表中的每一个节点进行申请空间
				//adj[i]指的是与第i个顶点直接相连的顶点所构成的节点链表
				adj[i]=new LinkedList<Integer>();//这里可以使用类型推断,在这里略去
			}
			
			E=scanner.nextInt();//再度入图的边数
			
			if(E<0)
			{//由于一个图最少有一个顶点,于是要考虑到方方面面的情况
				throw new IllegalArgumentException("E must be non-negative");
			}
			
			for(int i=0;i<E;i++)
			{
				//读入各个顶点的信息,顺带判断合法性
				int a=scanner.nextInt();
				validateVertex(a);
				int b=scanner.nextInt();
				validateVertex(b);
				
				//判断是否为自环边
				if(a==b)//如果某一条边的头尾节点都指向了同一个顶点,那么久认为这是一条自环边
				{
					throw new IllegalArgumentException("Self Loop is Detected!");
				}
				
				if(adj[a].contains(b))//如果已经有了这样的一条边,就认为他是一条平行边
				{
					throw new IllegalArgumentException("Parallel edges are detected!");
				}
				
				//根据各个顶点的信息,对邻接表进行追加元素操作
				adj[a].add(b);//基于无向图考虑
				adj[b].add(a);
			}
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	private void validateVertex(int v)
	{//判断边的信息是否正确,比如:有没有某一个边的序号小于0,或者大于V
		if(v<0||v>V)
		{
			throw new IllegalArgumentException("Vertex "+v+" is invalid");
		}
	}
	
	public int V()//为用户提供接口来访问节点数以及边数
	{
		return V;
	}
	
	public int E()
	{
		return E;
	}
	
	public boolean hasEdge(int v,int w)//判断两个顶点之间是否存在一条边
	{
		validateVertex(v);
		validateVertex(w);
		return adj[v].contains(w);
	}
	
	public LinkedList<Integer> adj(int v)//返回与顶点v相邻的边
	{
		validateVertex(v);
		return adj[v];
	}
	
	public int degree(int v)//返回某一节点的度
	{
		return adj(v).size();
	}
	
	@Override
	public String toString()//重写toString()方法来打印图
	{
		StringBuilder sb=new StringBuilder();//创建StringBuilder的对象用来操作字符串
		sb.append(String.format("V = %d,E = %d\n", V,E));//首先输出有关图的信息
		for(int v=0;v<V;v++)//v表示各个顶点的下标
		{
			sb.append(String.format("%d :", v));//控制输出的每一行的最左侧格式
			for(int w:adj[v])
			{
				sb.append(String.format("%d ", w));//使用增强for循环来对邻接表中的每一链表中的元素进行遍历
			}
			sb.append("\n");
		}
		return sb.toString();
	}
	
	public static void main(String []args)
	{
	
		AdjList adjList=new AdjList("g.txt");//传入图文件,并创建一个图

		System.out.println(adjList);
	}
}

值得注意的是:这里是用的测试用例仍然是使用邻接矩阵的测试文件,这里不再列出,总体上除了效率之外,我在这所实现的接口以及其他操作均是一样的。

发布了69 篇原创文章 · 获赞 33 · 访问量 1187

猜你喜欢

转载自blog.csdn.net/dosdiosas_/article/details/105693516