71 图的定义与操作
图的定义与操作
-
讨论中......
A:树中的结点可以有多个后继,而每个结点都只有一个直接前驱,因此形成了一种层次结构。 B:如果树中的每个结点也可以有多个直接前驱,那么这种层次结构都被破坏了。 C:这样子就形成了网状结构,会是一种新的数据结构么?
-
定义 图是由顶点集合(Vertex)及顶点间的关系集合(Edge)组成的一种数据结构: Graph=(V,E)
V={x|x∈某个数据对象}
是顶点的有穷非空集合E={(x,y)|x,y∈V}
是顶点之间关系的有穷集合 -
问题 思考:G1,G2,G3,G4都有图么?有什么异同?可以继续分类吗?
-
无向边
- 顶点x和y之间的边没有方向,则称该边为无向边
- (x,y)与(y,x)意义相同,表示x和y之间有连接
-
无向图
- 图中任意两个顶点之间的边均是无向边,则称该图为无向图
-
有向边
- 顶点x和y之间的边有方向,则称该边为有向边
<x,y>
与<y,x>
意义不同<x,y>
表示从x连接到y,x称为尾,y称为头<y,x>
表示从y连接到x,y称为尾,x称为头
-
有向图
- 图中任意两个顶点之间的边均是有向边,则称该图为有向图
-
有向图示例
无向图可以看作一种特殊的有向图!
-
顶点邻接(Adjacent)的定义
- 无向图
- 如果(x,y)∈E,则称顶点x和y互为邻接
- 有向图
- 如果< x,y >∈E,则称顶点x邻接到顶点y
- 无向图
-
度(Degree)的定义
- 顶点v的度是和v相关联的边的数目,记为TD(v)
- 入度:以v为头的边的数目,记为ID(v)
- 出度:以v为尾的边的数目,记为OD(v)
- 顶点v的度是和v相关联的边的数目,记为TD(v)
-
推论
- TD(v)=ID(v)+OD(V)
- Count(E)=ID(v1)+ID(v2)+...+ID(vn)
- Count(E)=OD(v1)+OD(v2)+...+OD(vn)
- Count(E)=[TD(v1)+TD(v2)+..+TD(vn)]/2
-
权(Weight)的定义
- 与图的边相关的数据元素叫做权
- 权常用来表示图中顶点间的距离或者耗费
-
图的一些常用的操作
- 设置顶点的值
- 获取顶点的值
- 获取邻接顶点
- 设置边的值
- 删除边
- 获取顶点树
- 获取边树
- ......
-
图在程序中表现为一种特殊的数据类型
templat<typename VertexType,typename EdgeType>
class Grap:public Object{
public:
virtual VertexType vertex(size_t index)=0;
virtual bool vertex(size_t index,VertexType &value)=0;
virtual bool setVertex(size_t index,const VertexType &value)=0;
virtual SharedPointer<Array<size_t>> adjacent(size_t index)=0;
virtual EdgeType egde(size_t begin,size_t end)=0;
virtual bool egde(size_t begin,size_t end,EdgeType &value)=0;
virtual bool setEdge(size_t begin,size_t end,cosnt EdgeType &value)=0;
virtual bool removeEdge(size_t begin,size_t end)=0;
virtual size_t vertexCount()=0;
virtual size_t edgeCount()=0;
virtual size_t outDegree(size_t index)=0;
virtual size_t inDegree(size_t index)=0;
virtual size_t degree(size_t index) {
return outDegree(index)+inDegree(index);
}
}
编程实验
-
图抽象类的创建
小结
- 图是顶点与边的集合,是一种非线性的数据结构
- 图中顶点可以与多个其它顶点 产生邻接关系
- 图中的边有与之对应的权值,表示顶点间的距离
- 图在程序中表现为特殊的数据类型
72 图的存储结构(上)
图的存储结构(上)
-
基本思想
- 用一维数组存储顶点:描述顶点相关的数据
- 用二维数组存储边:描述顶点间的关系和权
-
邻接矩阵法
-
设图A=(V,E)是一个有n个顶点的图。图的邻接矩阵为Edge[n][n],则:
注:解决工程问题时,习惯于对图中的每个顶点进行编号;当不需要权值时,取W非空表示结点间有连接。
-
-
邻接矩阵法示例一
-
无向图的邻接矩阵是对称的
-
-
邻接矩阵法示例二
-
有向图的邻接矩阵可能是不对称的
-
-
设计与实现
问题:如何具体表示顶点集数组?如何具体表示边集数组?
-
实现方式一:直接使用数组表示顶点集和边集
template<int N,typename VertexType,typename EdgeType>
class MatrixGraph:public Graph<VertexType,EdgeType>{
protected:
VertexType m_vertexes[N];
EdgeType m_edges[N][N];
int m_eCount;
public:
//...
} -
分析下面代码的效率
struct TV{
int a1[100];
char a2[1000];
TV(){/*init array*/}
};
struct TE{
float a1[100];
float a2[1000];
TE(){/*init array*/}
};
int main(){
MatrixGraph<1000,TV,TE> g;
} -
问题
- 构造效率低下
- 图对象初始化时,频繁调用顶点类型和边类型的构造函数
- 空间使用率低下
- 图对象占用大量空间,而大多数空间处于闲置状态
- 无法表示空值
- 无法用统一的方式表示边为空的情形
- 构造效率低下
-
实现方式二:使用指针数组表示顶点集和边集
template<int N,typename VertexType,typename EdgeType>
class MatrixGraph:public Graph<VertexType,EdgeType>{
protected:
VertexType *m_vertexes[N];
EdgeType *m_edges[N][N];
int m_eCount;
public:
//...
} -
问题的解决
- 构造效率
- 初始化图像时,只需要将数组元素赋值为空
- 空间使用率
- 顶点数据元素和边数据元素在需要时动态创建
- 空值的表示
- 任意的顶点类型和边类型都使用nullptr空值表示
- 构造效率
编程实验
-
图的邻接矩阵结构
小结
- 邻接矩阵法使用数组对图相关的数据进行存储
- 一维数组存储顶点相关的数据(空表示无相关的数据)
- 二维数组存储边相关的数据(空表示顶点间无连接)
- 代码实现时,使用指针数组进行数据的存储(提高效率)