图的遍历

1.  图的定义

      图是由顶点的有穷非空集合和顶点之间边的集合组成-----由图的定义可知,一个图包括两部分信息:顶点的信息以及顶点之间关系(边或弧)的信息

2.  图的存储

   2.1  邻接矩阵存储

    邻接矩阵存储:也称数组表示法,其方法是用一个一维数组存储图中顶点信息,用一个二维数组存储图中边的信息(各顶点之间的邻接关系),存储顶点之间的邻接关系的二维数组称为邻接矩阵


    邻接矩阵实现类:

package edu.tcu.soft;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

/*图的操作----邻接矩阵*/
public class MGraph<T> {

	private int[] vertex=new int[20]; // 存放顶点的数组
	private int[][] arc=new int[20][20]; // 存放边的数组
	private int vertexNum;// 存放顶点数
	private int arcNum; // 存放边数
	private int[] visited=new int[20]; // 是否被访问 0代表未访问、1代表已访问

	// 构造函数,建立具有n个顶点e条边的图
	public MGraph(T[] a, int n, int e) {
		vertexNum = n;
		arcNum = e;
		// 分别给各顶点赋值
		for (int i = 0; i < vertexNum; i++) {
			vertex[i] = (Integer) a[i];
			visited[i] = 0;
		}
		// 初始化邻接矩阵
		for (int j = 0; j < vertexNum; j++)
			for (int k = 0; k < vertexNum; k++)
				arc[j][k] = 0;
		// 依次输入每一条边
		for (int r = 0; r < arcNum; r++) {
			@SuppressWarnings("resource")
			Scanner scanner = new Scanner(System.in);
			int i = scanner.nextInt();
			int j = scanner.nextInt();
			arc[i][j] = 1;
			arc[j][i] = 1;
		}
	}

	// 深度遍历图
	public void depthTraverse(int v) {
		System.out.print(vertex[v] + "  ");
		visited[v] = 1; // 将该结点设置为已经被访问
		for (int i = 0; i < vertexNum; i++)
			// v、i两个结点之间有边,且i结点还没被访问
			if (arc[v][i] == 1 && visited[i] == 0)
				depthTraverse(i);
	}

	// 广度遍历图
	public void broadthTraverse(int v) {
		Queue<Integer> queue = new LinkedList<>();// 队列
		System.out.println(vertex[v] + "  ");
		visited[v] = 1; // 将该结点设置为已经被访问
		queue.add(v);
		// 队列不为空
		while (!queue.isEmpty()) {
			int ver = queue.poll();
			for (int j = 0; j < vertexNum; j++)
				if (arc[ver][j] == 1 && visited[j] == 0) {
					System.out.println(vertex[v] + "  ");
					visited[j] = 1; // 将该结点设置为已经被访问
					queue.add(j);
				}
		}
	}
}
  

邻接矩阵测试类:

package edu.tcu.soft;
public class Test {
   public static void main(String[] args) {
	Integer[] a=new Integer[]{2,3,5,7};
	MGraph<Integer> graph=new MGraph<>(a, 4, 4);
	graph.depthTraverse(3);
}
}

    2.2  邻接表存储

    邻接表是一种顺序存储和链接存储相结合的存储方法,类似于树的孩子链表表示法,存储边表头指针的数组和存储顶点信息的数组构成了表头数组,称为顶点表。所以在邻接表中存在两种结点结构:顶点表结点和边表结点。


顶点表实现类:

package edu.tcu.soft;

/*顶点表结点*/
public class VertexNode<T> {

	private T vertex; // 存放顶点信息
	private ArcNode arcNode; // 存放边表中的第一个结点

	public T getVertex() {
		return vertex;
	}

	public void setVertex(T vertex) {
		this.vertex = vertex;
	}

	public ArcNode getArcNode() {
		return arcNode;
	}

	public void setArcNode(ArcNode arcNode) {
		this.arcNode = arcNode;
	}

	public VertexNode(T vertex, ArcNode arcNode) {
		super();
		this.vertex = vertex;
		this.arcNode = arcNode;
	}

}

边表实现类:

package edu.tcu.soft;
/*边表数据结构*/
public class ArcNode {

	private int adjvex; // 存放顶点表下标
	private ArcNode arcNode; // 边表的下一个结点

	public int getAdjvex() {
		return adjvex;
	}

	public void setAdjvex(int adjvex) {
		this.adjvex = adjvex;
	}

	public ArcNode getArcNode() {
		return arcNode;
	}

	public void setArcNode(ArcNode arcNode) {
		this.arcNode = arcNode;
	}

}

邻接表实现类:

package edu.tcu.soft;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
/*邻接表实现类*/
public class LGraph<T> {

	@SuppressWarnings({"unchecked" })
	private VertexNode<T>[] vertexNode=new VertexNode[5]; // 顶点表数组
	private int vertexNum; // 图的顶点数
	private int arcNum; // 图的边数
	private int[] visited=new int[4];//0代表未访问,1代表已访问

	/* 构造函数,建立一个具有n个顶点e条边的图 */
	@SuppressWarnings({"resource" })
	public LGraph(T a[], int n, int e) {
		vertexNum = n;
		arcNum = e;
		// 输入顶点信息,初始化顶点表
		for (int i = 0; i < vertexNum; i++) {
			visited[i]=0;   //设置该顶点未访问
			vertexNode[i]=new VertexNode<T>(a[i], null);
		}
		//依次输入每一条边
		for(int k=0;k<arcNum;k++){
			Scanner scanner=new Scanner(System.in);
			int i=scanner.nextInt();
			int j=scanner.nextInt();
			ArcNode arcNode=new ArcNode(); //实例化边表
			arcNode.setAdjvex(j);          //设置边表的顶点表下标
			arcNode.setArcNode(vertexNode[i].getArcNode());//设置边表的下一个结点
			
			ArcNode arcNode1=new ArcNode(); //实例化边表
			arcNode1.setAdjvex(i);          //设置边表的顶点表下标
			arcNode1.setArcNode(vertexNode[j].getArcNode());//设置边表的下一个结点
			
			vertexNode[i].setArcNode(arcNode);  //设置顶点表的第一个边表结点
			vertexNode[j].setArcNode(arcNode1);  //设置顶点表的第一个边表结点
		}
	}

	// 深度遍历
	public void depthTraverse(int v) {
       System.out.print(vertexNode[v].getVertex()+"  ");
       visited[v]=1;//设置已访问
       ArcNode node=vertexNode[v].getArcNode();
       while(node!=null){
    	   int j=node.getAdjvex();
    	   if(visited[j]==0)
    		   depthTraverse(j);
    	   node=node.getArcNode();
       }
	}

	// 广度遍历
	public void broadthTraverse(int v) {
		Queue<Integer> queue=new LinkedList<>();
        System.out.print(vertexNode[v].getVertex()+"  ");
        visited[v]=1;
        queue.add(v);
        while(!queue.isEmpty()){
        	int i=queue.poll();
        	ArcNode node=vertexNode[i].getArcNode(); //获取顶点表的第一个边表
        	while(node!=null){
        		int j=node.getAdjvex();
        		if(visited[j]==0){
        			System.out.print(vertexNode[j].getVertex()+"  ");
        			visited[j]=1;
        			queue.add(j);
        		}
        		node=node.getArcNode();
        	}
        }
	}
}

测试类:

package edu.tcu.soft;
public class Test {
   public static void main(String[] args) {
	Integer[] a=new Integer[]{2,3,5,7};
	LGraph<Integer> graph2=new LGraph<>(a, 4, 4);
	graph2.broadthTraverse(3);
}
}

    2.3  邻接矩阵和邻接表的比较

    邻接矩阵和邻接表是图的两种常用的存储结构,均可用于存储有向图和无向图,也均可用于存储网图。设图G含有n个顶点e条边,下面比较邻接矩阵和邻接表存储结构

    1.空间性能比较

     邻接矩阵:邻接矩阵是一个n*n的矩阵,空间代价是O(n*n)

     邻接表:邻接表的空间代价与图的边数及顶点数有关,每一顶点在顶点表中都要占据一个数组元素的位置(即使该顶点没有邻接点),且每条边必须出现在某个顶点的边表中,所以当图是有向图时,邻接表的空间代价是O(n+e);当图是无线图是,邻接表的空间 代价是O(n+2*e)

     哪种表示方法的存储效率高图中边的数目。邻接表仅存储实际实际出现在图中的边,而邻接矩阵则需要存储所有可能的边,但是邻接矩阵不需要结构性开销。一般情况下,图越稠密,邻接矩阵的空间效率越高,而对稀疏图(e<nlogn,n是图的顶点数,e是边数)使用邻接表,则能获得较高的空间效率。

     2.时间性能比较

     邻接矩阵在图的算法中时间代价比邻接表的高,原因是:在图的算法中访问某个顶点的所有邻接点是较常见的操作。如果使用邻接表,只需要检查此顶点的边表,即只检查与它相邻的实际存在的边,平均需要查找O(e/n)次;如果使用邻接矩阵,则必须检查所有可能的边,需要查找O(n)次


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值