【数据结构】图

转载来自:数据结构之图



一、基本术语


:由有穷、非空点集和边集合组成,简写成G(V,E);

Vertex:图中的顶点;


无向图:图中每条边都没有方向;

有向图:图中每条边都有方向;


无向边:边是没有方向的,写为(a,b)

有向边:边是有方向的,写为<a,b>

有向边也成为弧;开始顶点称为弧尾,结束顶点称为弧头;


简单图:不存在指向自己的边、不存在两条重复的边的图;


无向完全图:每个顶点之间都有一条边的无向图;

有向完全图:每个顶点之间都有两条互为相反的边的无向图;


稀疏图:边相对于顶点来说很少的图;

稠密图:边很多的图;


权重:图中的边可能会带有一个权重,为了区分边的长短;

:带有权重的图;


:与特定顶点相连接的边数;

出度、入度:对于有向图的概念,出度表示此顶点为起点的边的数目,入度表示此顶点为终点的边的数目;


:第一个顶点和最后一个顶点相同的路径;

简单环:除去第一个顶点和最后一个顶点后没有重复顶点的环;


连通图:任意两个顶点都相互连通的图;

极大连通子图:包含竟可能多的顶点(必须是连通的),即找不到另外一个顶点,使得此顶点能够连接到此极大连通子图的任意一个顶点;

连通分量:极大连通子图的数量;

强连通图:此为有向图的概念,表示任意两个顶点a,b,使得a能够连接到b,b也能连接到a 的图;


生成树:n个顶点,n-1条边,并且保证n个顶点相互连通(不存在环);

最小生成树:此生成树的边的权重之和是所有生成树中最小的;


AOV网:结点表示活动的网;

AOE网:边表示活动的持续时间的网;


二、图的存储结构


1.邻接矩阵


维持一个二维数组,arr[i][j]表示i到j的边,如果两顶点之间存在边,则为1,否则为0;

维持一个一维数组,存储顶点信息,比如顶点的名字;

下图为一般的有向图:


注意:如果我们要看vi节点邻接的点,则只需要遍历arr[i]即可;


 下图为带有权重的图的邻接矩阵表示法:

 

缺点:邻接矩阵表示法对于稀疏图来说不合理,因为太浪费空间; 


2.邻接表


如果图示一般的图,则如下图:


 如果是网,即边带有权值,则如下图:



3.十字链表

只针对有向图;,适用于计算出度和入度;

顶点结点:

 

边结点:

 

好处:创建的时间复杂度和邻接链表相同,但是能够同时计算入度和出度;

4.邻接多重表

针对无向图; 如果我们只是单纯对节点进行操作,则邻接表是一个很好的选择,但是如果我们要在邻接表中删除一条边,则需要删除四个顶点(因为无向图);

在邻接多重表中,只需要删除一个节点,即可完成边的删除,因此比较方便;

因此邻接多重表适用于对边进行删除的操作;

顶点节点和邻接表没区别,边表节点如下图:


比如:

 


5.边集数组


合依次对边进行操作;

存储边的信息,如下图:


图的JAVA实现:

public class Graph<E> implements Cloneable
{
	private boolean[][] edges;
	private E[] labels;
	
	public Graph (int n)
	{
		edges = new boolean[n][n];
		labels = (E[]) new Object[n];
		int i,j;
		
		for (i = 0; i < n; i++)
			for (j = 0; j < n; j++)
			{
				edges[i][j] = false;
			}
	}
	
	// 增加一条边
	public void addEdge(int source, int target)
	{
		edges[source][target] = true;
	}
	
	// 测试一条边是否存在
	public boolean isEdge(int source, int target)
	{
		return edges[source][target];
	}
	
	// 删除该Graph的一条边
	public void removeEdge(int source, int target)
	{
		edges[source][target] = false;
	}

	// 生成一个该Graph的副本
	public Graph<E> clone()
	{
		Graph<E> answer;
		
		try
		{
			answer = (Graph<E>) super.clone();
		} catch (Exception e)
		{
			throw new RuntimeException("This class does not implement Cloneable");
		}
		
		answer.edges = edges.clone();
		answer.labels = labels.clone();
		
		return answer;
	}
	
	// 用于获取该Graph的某个顶点标签
	public E getlabel(int vertex)
	{
		return labels[vertex];
	}
	
	// 改变该Graph的顶点标签
	public void setLabel(int vertex, E newLabel)
	{
		labels[vertex] = newLabel;
	}
	
	// 用于获取该graph中指定顶点的邻接点列表
	public int[] neighbors(int vartex)
	{
		int i;
		int count;
		int[] answer;
		
		count = 0;
		// 首先计算有多少条边以该顶点为起点
		for (i = 0; i < labels.length; i++)
		{
			if (edges[vartex][i])
			{
				count++;
			}
		}
		
		answer = new int[count];
		
		count = 0;
		for (i = 0; i < labels.length; i++)
		{
			if (edges[vartex][i])
			{
				answer[count++] = i;
			}
		}
		
		return answer;
	}
	
	// 表示确定该Graph中顶点的数目
	public int size()
	{
		return labels.length;
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值