ericliwang

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: :: 管理 ::

一、图的抽象数据结构类型:

ADT Graph{
	数据对象V:V是具有相同特性的数据元素的集合,称为顶点集。
		数据关系R:R={VR}
	VR={<v,w>|v,w∈V且P(v,w),<v,w>表示从v到w的弧,
		谓词P(v,w)定义了弧<v,w>的意义或信息}
	基本操作:
	CreateGraph( &G, V, VR )
	初始条件:V是图的顶点集,VR是图中弧的集合。
	操作结果:按V和VR的定义构造图G。
	DestroyGraph( &G )
	初始条件:图G存在。
	操作结果:销毁图G。
	LocateVex( G, u )
	初始条件:图G存在,u和G中顶点有相同特征。
	操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回其它信息。
	GetVex( G, v )
	初始条件:图G存在,v是G中某个顶点。
	操作结果:返回v的值。
	PutVex( &G, v, value )
	初始条件:图G存在,v是G中某个顶点。
	操作结果:对v赋值value。
	FirstAdjVex( G, v )
	初始条件:图G存在,v是G中某个顶点。
	操作结果:返回v的第一个邻接顶点。若顶点在G中没有邻接顶点,则返回“空”。
	NextAdjVex( G, v, w )
	初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点。
	操作结果:返回v的(相对于w的)下一个邻接顶点。若w是v的最后一个邻接点,则返回“空”。
	InsertVex( &G, v )
	初始条件:图G存在,v和图中顶点有相同特征。
	操作结果:在图G中增添新顶点v。
	DeleteVex( &G, v )
	初始条件:图G存在,v是G中某个顶点。
	操作结果:删除G中顶点v及其相关的弧。
	InsertArc( &G, v, w )
	初始条件:图G存在,v和w是G中两个顶点。
	操作结果:在G中增添弧<v,w>,若G是无向的,则还增添对称弧<v,w>。
	DeleteArc( &G, v, w )
	初始条件:图G存在,v和w是G中两个顶点。
	操作结果:在G中删除弧<v,w>,若G是无向的,则还删除对称弧<v,w>。
	DFSTraverse( G, Visit() )
	初始条件:图G存在,Visit是顶点的应用函数。
	操作结果:对图进行深度优先遍历。在遍历过程中对每个顶点调用函数Visit一次且仅一次。一旦visit()失败,则操作失败。
	BFSTraverse( G, Visit() )
	初始条件:图G存在,Visit是顶点的应用函数。
	操作结果:对图进行广度优先遍历。在遍历过程中对每个顶点调用函数Visit一次且仅一次。一旦visit()失败,则操作失败。
}ADT Graph

 

二、图的存储结构:

1.数组表示法:

#define INFINITY INT_MAX     //最大值
#define MAX_VERTEX_NUM 20    //最大顶点数
typedef enum {DG,DN,UDG,UDN} GraphKind; //DG表示有向图, DN表示有向网, UDG表示无向图, UDN表示无向网 
typedef struct ArcNode
{ 
	VRType adj; //VRType是顶点关系类型。对于无权图,用1或0表示相邻否;对带权图,则为权值类型。
	char * info;//该弧相关信息的指针 
}ArcNode, AdjMatrix[MAX_V_N][MAX_V_N];//邻接矩阵 
typedef struct { 
	VertexType vexs[MAX_VERTEX_NUM]; //顶点向量
	AdjMatrix arcs;                  //邻接矩阵
	int vexnum,arcnum;               //图的当前顶点数和弧数
	GraphKind kind;                  //图的种类标志
}MGraph;

 

Status CreateGraph( MGraph &G ) 
{
	// 采用数组(邻接矩阵)表示法,构造图G。
	scanf(&G.kind);  // 自定义输入函数,读入一个随机值
	switch (G.kind) {
		case  DG: return CreateDG(G);   // 构造有向图G
		case  DN: return CreateDN(G);   // 构造有向网G
		case UDG: return CreateUDG(G);  // 构造无向图G
		case UDN: return CreateUDN(G);  // 构造无向网G
		default : return ERROR;
	}
}

 

Status CreateUDN(MGraph &G) 
{
	// 采用数组(邻接矩阵)表示法,构造无向网G。
	scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &IncInfo);      
	for (i=0; i<G.vexnum; i++ )
		scanf("%c",&G.vexs[i]);  // 构造顶点向量
	for (i=0; i<G.vexnum; ++i )  // 初始化邻接矩阵
		for (j=0; j<G.vexnum; ++j ) 
		{
			G.arcs[i][j].adj = INFINITY; 
			G.arcs[i][j].info= NULL;
		}
		for (k=0; k<G.arcnum; ++k ) 
		{  
			// 构造邻接矩阵
			scanf(&v1,&v2,&w);        // 输入一条边依附的顶点及权值
			i = LocateVex(G, v1);  j = LocateVex(G, v2);  // 确定v1和v2在G中位置  
			G.arcs[i][j].adj = w;                // 弧<v1,v2>的权值
			if (IncInfo) scanf(G.arcs[i][j].info); // 输入弧含有相关信息
			G.arcs[j][i].adj = G.arcs[i][j].adj; // 置<v1,v2>的对称弧<v2,v1>
		}
	return OK;
} 

 

二、邻接表:

1.结点的结构:

2.邻接表和逆邻接表:

(<有向图的>逆邻接表:对每个顶点vi建立一个以vi为头的链表,便于确定顶点的入读或以顶点vi为头的弧。)

3.邻接表的实现:

//表结点的结构
typedef struct ArcNode {   
	int adjvex;                 //该弧所指向的顶点的位置
	struct ArcNode *nextarc;    //指向下一条弧的指针
	InfoType *info;             //该弧相关信息的指针(如权值)
}ArcNode;

//头结点结构
typedef struct VNode {   
	VertexType data;            //顶点信息
	ArcNode *firstarc;          //指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM];

//图的结构
typedef struct {
	AdjList vexs;               
	int vexnum,arcnum;          //图的当前顶点数和弧数
	int kind;                   //图的种类标志
}ALGraph;

 

//------------------图的构造函数------------------------
void CreateALGraph(ALGraph &G) 
{
	scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &G.kind);
	for (i=0; i<G.vexnum; i++) 
	{   
		//初始化头结点
		cin >> G.vexs[i].data;
		G.vexs[i].firstarc = NULL;
	}
	for (k=0; k<G.arcnum; k++) 
	{   
		scanf(&v1,&v2,&w);        // 输入一条边依附的顶点及权值
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = j;
		p->info = w;
		p->nextarc = G.vexs[i].firstarc;
		G.vexs[i].firstarc = p;

		if (G.kind==UDG) 
		{    
			//如果是无向图,执行此步骤
			p=(ArcNode*)malloc(sizeof(ArcNode));
			p->adjvex=i;	        
			p->info = w;
			p->nextarc=G.vexs[j].firstarc;
			G.vexs[j].firstarc=p;
		}
	}
}

 

三、十字链表:

1.结点结构:

     

  在弧结点中有五个域:其中尾域(tailvex)和头域(headvex)分别指示弧尾和弧头这两个顶点在图中的位置,链域hlink指向弧头相同的下一条弧,而链域tlink指向弧尾相同的下一条弧,info域指向该弧的相关信息。弧头相同的弧在同一链表上,弧尾相同的弧也在同一链表上。

  头结点即为顶点结点,它由三个域组成:其中data域存储和顶点相关的信息,如顶点的名称等;firstin和firstout为两个链域,分别指向以该顶点为弧头或弧尾的第一个弧结点。

2.十字链表:

3.十字链表的实现:

Status CreateDG(OLGraph &G) 
{ 
	// 采用十字链表存储表示,构造有向图G(G.kind=DG)。
	scanf(&G.vexnum, &G.arcnum, &IncInfo);  // 自定义输入函数
	for (i=0; i<G.vexnum; ++i) 
	{            
		// 构造表头向量
		scanf(&G.xlist[i].data);              // 输入顶点值
		G.xlist[i].firstin = G.xlist[i].firstout = NULL;  // 初始化指针
	}
	for (k=0; k<G.arcnum; ++k)
	{  
		// 输入各弧并构造十字链表
		scanf(&v1, &v2);            // 输入一条弧的始点和终点
		i=LocateVex(G, v1);  j=LocateVex(G, v2); // 确定v1和v2在G中位置
		p=(ArcBox *) malloc (sizeof (ArcBox));     // 假定有足够空间
		*p = {i, j, G.xlist[j].firstin, G.xlist[i].firstout, NULL} 
		// {tailvex, headvex, hlink, tlink, info}
		G.xlist[j].firstin = G.xlist[i].firstout = p; 
        // 完成在入弧和出弧链头的插入
		if (IncInfo) Input(*p->info); // 输入弧含有相关信息
	}
	return OK;
} 

......

posted on 2010-11-30 22:15  ericliwang  阅读(488)  评论(0编辑  收藏  举报