无向图的邻接多重表存储实现(第七章 P166)

 

 

 

无向图的邻接多重表存储结构:

 

 

上图是根据程序定义的无向图的存储结构。程序中基本操作函数 CreateGraph ()  是在表头插入边结点的。所以,对于给定的图,它的边结点的链表结构也不惟一,与边的输入顺序有关。采用邻接多重表存储结构, 每条边只生成一个结点。而用邻接表存储结构表示无向图,图的每条边生成两个结点。
 
 
 
无向图及其邻接多重表存储结构:

 

 

在无向图中边的两个顶点是没有顺序的,顶点是根据与其顶点号对应的指针域形成邻接顶点链表的。
 
如图上图( a ) 所示,上排权值分别是 5 4 3 3 个结点形成与 v1 相连的 3 条边。它们的 jvex=0 ,从头指针 adjmulist [ 0 ]. firstedge 指向上排左边结点 ( 这个结点表示连接顶点 v1 v3 的边,因为它的 jvex ivex 分别为 0 2 ) 开始,通过 jlink 指针链接在一起。与某一顶点相连的边不一定都由 ilink jlink 指向,它取决于结点的 ivex jvex 中 的 哪 一 个 与 该 顶 点 的 序 号 相 同 。 以 与 顶 点 v3 相 连 的 边 为 例 , 从 头 指 针 adjmulist[ 2 ]. firstedge 指向上排左边结点,因为该结点的 ivex=2 ,所以,该结点的 ilink 指向与顶点 v3 相连的下一条边 ( 下排左边结点 ) 。而这个结点的 jvex=2 ,则该结点的 jlink 指向与顶点 v3 相连的下一条边 ( 下排右边结点 ) 。这个结点的 jvex=2 jlink=NULL ,表明链表结束,不再有与顶点 v3 相连的边。这样,与顶点 v3 邻接的顶点有 3 个,依次是 v1 v4 和 v2 。与图示相符。
 
 
虽然邻接多重表存储结构也是不带头结点的单链表结构,但由于指向下一结点的指针域是变化的,可能是 ilink 指向下一个结点,也可能是 jlink 指向下一个结点,这取决于 ivex 和 jvex 的值。所以不带头结点的单链表基本操作应用于邻接多重表  存储结构的基本操作中很不方便,这使得邻接多重表存储结构的基本操作比较冗长。
 
 
 
 
 
 
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */

#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
#include<limits.h> //常量INT_MAX和INT_MIN分别表示最大、最小整数

/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2 

#define MAX_NAME 3 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 80 /* 相关信息字符串的最大长度+1 */
typedef char InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */


/* ---------------------------------  无向图的邻接多重表存储表示    --------------------------------*/

#define MAX_VERTEX_NUM 20
typedef enum { unvisited, visited }VisitIf;
typedef struct EBox
{
	VisitIf mark; /* 访问标记 */
	int ivex, jvex; /* 该边依附的两个顶点的位置 */
	struct EBox *ilink, *jlink; /* 分别指向依附这两个顶点的下一条边 */
	InfoType *info; /* 该边信息指针 */
}EBox;
typedef struct
{
	VertexType data;
	EBox *firstedge; /* 指向第一条依附该顶点的边 */
}VexBox;
typedef struct
{
	VexBox adjmulist[MAX_VERTEX_NUM];
	int vexnum, edgenum; /* 无向图的当前顶点数和边数 */
}AMLGraph;

/* ---------------------------------------------------------------------------------------------*/




/* ---------------------------  无向图的邻接多重表存储的基本函数类型(16个) --------------------------*/


int LocateVex(AMLGraph G, VertexType u)
{ /* 初始条件: 无向图G存在,u和G中顶点有相同特征 */
  /* 操作结果: 若G中存在顶点u,则返回该顶点在无向图中位置;否则返回-1 */
	int i;
	for (i = 0; i < G.vexnum; ++i)
		if (strcmp(u, G.adjmulist[i].data) == 0)
			return i;
	return -1;
}

Status CreateGraph(AMLGraph *G)
{ /* 采用邻接多重表存储结构,构造无向图G */
	int i, j, k, l, IncInfo;
	char s[MAX_INFO];
	VertexType va, vb;
	EBox *p;
	printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
	scanf("%d,%d,%d", &(*G).vexnum, &(*G).edgenum, &IncInfo);
	printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
	for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
	{
		scanf("%s", (*G).adjmulist[i].data);
		(*G).adjmulist[i].firstedge = NULL;
	}
	printf("请顺序输入每条边的两个端点(以空格作为间隔):\n");
	for (k = 0; k < (*G).edgenum; ++k) /* 构造表结点链表 */
	{
		scanf("%s%s%*c", va, vb); /* %*c吃掉回车符 */
		i = LocateVex(*G, va); /* 一端 */
		j = LocateVex(*G, vb); /* 另一端 */
		p = (EBox*)malloc(sizeof(EBox));
		p->mark = unvisited; /* 设初值 */
		p->ivex = i;
		p->jvex = j;
		p->info = NULL;
		p->ilink = (*G).adjmulist[i].firstedge; /* 插在表头 */
		(*G).adjmulist[i].firstedge = p;
		p->jlink = (*G).adjmulist[j].firstedge; /* 插在表头 */
		(*G).adjmulist[j].firstedge = p;
		if (IncInfo) /* 边有相关信息 */
		{
			printf("请输入该弧的相关信息(<%d个字符):", MAX_INFO);
			gets(s);
			l = strlen(s);
			if (l)
			{
				p->info = (char*)malloc((l + 1) * sizeof(char));
				strcpy(p->info, s);
			}
		}
	}
	return OK;
}

VertexType* GetVex(AMLGraph G, int v)
{ /* 初始条件: 无向图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
	if (v >= G.vexnum || v < 0)
		exit(ERROR);
	return &G.adjmulist[v].data;
}

Status PutVex(AMLGraph *G, VertexType v, VertexType value)
{ /* 初始条件: 无向图G存在,v是G中某个顶点 */
  /* 操作结果: 对v赋新值value */
	int i;
	i = LocateVex(*G, v);
	if (i < 0) /* v不是G的顶点 */
		return ERROR;
	strcpy((*G).adjmulist[i].data, value);
	return OK;
}

int FirstAdjVex(AMLGraph G, VertexType v)
{ /* 初始条件: 无向图G存在,v是G中某个顶点 */
  /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
	int i;
	i = LocateVex(G, v);
	if (i < 0)
		return -1;
	if (G.adjmulist[i].firstedge) /* v有邻接顶点 */
		if (G.adjmulist[i].firstedge->ivex == i)
			return G.adjmulist[i].firstedge->jvex;
		else
			return G.adjmulist[i].firstedge->ivex;
	else
		return -1;
}

int NextAdjVex(AMLGraph G, VertexType v, VertexType w)
{ /* 初始条件: 无向图G存在,v是G中某个顶点,w是v的邻接顶点 */
  /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
  /*           若w是v的最后一个邻接点,则返回-1 */
	int i, j;
	EBox *p;
	i = LocateVex(G, v); /* i是顶点v的序号 */
	j = LocateVex(G, w); /* j是顶点w的序号 */
	if (i < 0 || j < 0) /* v或w不是G的顶点 */
		return -1;
	p = G.adjmulist[i].firstedge; /* p指向顶点v的第1条边 */
	while (p)
		if (p->ivex == i && p->jvex != j) /* 不是邻接顶点w(情况1) */
			p = p->ilink; /* 找下一个邻接顶点 */
		else if (p->jvex == i && p->ivex != j) /* 不是邻接顶点w(情况2) */
			p = p->jlink; /* 找下一个邻接顶点 */
		else /* 是邻接顶点w */
			break;
	if (p&&p->ivex == i && p->jvex == j) /* 找到邻接顶点w(情况1) */
	{
		p = p->ilink;
		if (p&&p->ivex == i)
			return p->jvex;
		else if (p&&p->jvex == i)
			return p->ivex;
	}
	if (p&&p->ivex == j && p->jvex == i) /* 找到邻接顶点w(情况2) */
	{
		p = p->jlink;
		if (p&&p->ivex == i)
			return p->jvex;
		else if (p&&p->jvex == i)
			return p->ivex;
	}
	return -1;
}

Status InsertVex(AMLGraph *G, VertexType v)
{ /* 初始条件: 无向图G存在,v和G中顶点有相同特征 */
  /* 操作结果: 在G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
	if ((*G).vexnum == MAX_VERTEX_NUM) /* 结点已满,不能插入 */
		return ERROR;
	if (LocateVex(*G, v) >= 0) /* 结点已存在,不能插入 */
		return ERROR;
	strcpy((*G).adjmulist[(*G).vexnum].data, v);
	(*G).adjmulist[(*G).vexnum].firstedge = NULL;
	(*G).vexnum++;
	return OK;
}

Status DeleteArc(AMLGraph *G, VertexType v, VertexType w)
{ /* 初始条件: 无向图G存在,v和w是G中两个顶点 */
  /* 操作结果: 在G中删除弧<v,w> */
	int i, j;
	EBox *p, *q = NULL;
	i = LocateVex(*G, v);
	j = LocateVex(*G, w);
	if (i < 0 || j < 0 || i == j)
		return ERROR;  /* 图中没有该点或弧 */
	  /* 以下使指向待删除边的第1个指针绕过这条边 */
	p = (*G).adjmulist[i].firstedge; /* p指向顶点v的第1条边 */
	if (p&&p->jvex == j) /* 第1条边即为待删除边(情况1) */
		(*G).adjmulist[i].firstedge = p->ilink;
	else if (p&&p->ivex == j) /* 第1条边即为待删除边(情况2) */
		(*G).adjmulist[i].firstedge = p->jlink;
	else /* 第1条边不是待删除边 */
	{
		while (p) /* 向后查找弧<v,w> */
		{
			if (p->ivex == i && p->jvex != j) /* 不是待删除边 */
			{
				q = p;
				p = p->ilink; /* 找下一个邻接顶点 */
			}
			else if (p->jvex == i && p->ivex != j) /* 不是待删除边 */
			{
				q = p;
				p = p->jlink; /* 找下一个邻接顶点 */
			}
			else /* 是邻接顶点w */
				break;
		}
		if (!p) /* 没找到该边 */
			return ERROR;
		if (p->ivex == i && p->jvex == j) /* 找到弧<v,w>(情况1) */
			if (q->ivex == i)
				q->ilink = p->ilink;
			else
				q->jlink = p->ilink;
		else if (p->ivex == j && p->jvex == i) /* 找到弧<v,w>(情况2) */
			if (q->ivex == i)
				q->ilink = p->jlink;
			else
				q->jlink = p->jlink;
	}
	/* 以下由另一顶点起找待删除边且删除之 */
	p = (*G).adjmulist[j].firstedge; /* p指向顶点w的第1条边 */
	if (p->jvex == i) /* 第1条边即为待删除边(情况1) */
	{
		(*G).adjmulist[j].firstedge = p->ilink;
		if (p->info) /* 有相关信息 */
			free(p->info);
		free(p);
	}
	else if (p->ivex == i) /* 第1条边即为待删除边(情况2) */
	{
		(*G).adjmulist[j].firstedge = p->jlink;
		if (p->info) /* 有相关信息 */
			free(p->info);
		free(p);
	}
	else /* 第1条边不是待删除边 */
	{
		while (p) /* 向后查找弧<v,w> */
			if (p->ivex == j && p->jvex != i) /* 不是待删除边 */
			{
				q = p;
				p = p->ilink; /* 找下一个邻接顶点 */
			}
			else if (p->jvex == j && p->ivex != i) /* 不是待删除边 */
			{
				q = p;
				p = p->jlink; /* 找下一个邻接顶点 */
			}
			else /* 是邻接顶点v */
				break;
		if (p->ivex == i && p->jvex == j) /* 找到弧<v,w>(情况1) */
		{
			if (q->ivex == j)
				q->ilink = p->jlink;
			else
				q->jlink = p->jlink;
			if (p->info) /* 有相关信息 */
				free(p->info);
			free(p);
		}
		else if (p->ivex == j && p->jvex == i) /* 找到弧<v,w>(情况2) */
		{
			if (q->ivex == j)
				q->ilink = p->ilink;
			else
				q->jlink = p->ilink;
			if (p->info) /* 有相关信息 */
				free(p->info);
			free(p);
		}
	}
	(*G).edgenum--;
	return OK;
}

Status DeleteVex(AMLGraph *G, VertexType v)
{ /* 初始条件: 无向图G存在,v是G中某个顶点 */
  /* 操作结果: 删除G中顶点v及其相关的边 */
	int i, j;
	VertexType w;
	EBox *p;
	i = LocateVex(*G, v); /* i为待删除顶点的序号 */
	if (i < 0)
		return ERROR;
	for (j = 0; j < (*G).vexnum; j++) /* 删除与顶点v相连的边(如果有的话) */
	{
		if (j == i)
			continue;
		strcpy(w, *GetVex(*G, j)); /* w是第j个顶点的值 */
		DeleteArc(G, v, w);
	}
	for (j = i + 1; j < (*G).vexnum; j++) /* 排在顶点v后面的顶点的序号减1 */
		(*G).adjmulist[j - 1] = (*G).adjmulist[j];
	(*G).vexnum--; /* 顶点数减1 */
	for (j = i; j < (*G).vexnum; j++) /* 修改顶点的序号 */
	{
		p = (*G).adjmulist[j].firstedge;
		if (p)
		{
			if (p->ivex == j + 1)
			{
				p->ivex--;
				p = p->ilink;
			}
			else
			{
				p->jvex--;
				p = p->jlink;
			}
		}
	}
	return OK;
}

void DestroyGraph(AMLGraph *G)
{
	int i;
	for (i = (*G).vexnum - 1; i >= 0; i--)
		DeleteVex(G, (*G).adjmulist[i].data);
}

Status InsertArc(AMLGraph *G, VertexType v, VertexType w)
{ /* 初始条件: 无向图G存在,v和W是G中两个顶点 */
  /* 操作结果: 在G中增添弧<v,w> */
	int i, j, l, IncInfo;
	char s[MAX_INFO];
	EBox *p;
	i = LocateVex(*G, v); /* 一端 */
	j = LocateVex(*G, w); /* 另一端 */
	if (i < 0 || j < 0)
		return ERROR;
	p = (EBox*)malloc(sizeof(EBox));
	p->mark = unvisited;
	p->ivex = i;
	p->jvex = j;
	p->info = NULL;
	p->ilink = (*G).adjmulist[i].firstedge; /* 插在表头 */
	(*G).adjmulist[i].firstedge = p;
	p->jlink = (*G).adjmulist[j].firstedge; /* 插在表头 */
	(*G).adjmulist[j].firstedge = p;
	printf("该边是否有相关信息(1:有 0:无): ");
	scanf("%d%*c", &IncInfo); /* 吃掉回车符 */
	if (IncInfo) /* 边有相关信息 */
	{
		printf("请输入该边的相关信息(<%d个字符):", MAX_INFO);
		gets(s);
		l = strlen(s);
		if (l)
		{
			p->info = (char*)malloc((l + 1) * sizeof(char));
			strcpy(p->info, s);
		}
	}
	(*G).edgenum++;
	return OK;
}

Boolean visite[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
Status(*VisitFunc)(VertexType v);
void DFS(AMLGraph G, int v)
{
	int j;
	EBox *p;
	VisitFunc(G.adjmulist[v].data);
	visite[v] = TRUE;
	p = G.adjmulist[v].firstedge;
	while (p)
	{
		j = p->ivex == v ? p->jvex : p->ivex;
		if (!visite[j])
			DFS(G, j);
		p = p->ivex == v ? p->ilink : p->jlink;
	}
}

void DFSTraverse(AMLGraph G, Status(*visit)(VertexType))
{ /* 初始条件: 图G存在,Visit是顶点的应用函数。算法7.4 */
  /* 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit */
  /*           一次且仅一次。一旦Visit()失败,则操作失败 */
	int v;
	VisitFunc = visit;
	for (v = 0; v < G.vexnum; v++)
		visite[v] = FALSE;
	for (v = 0; v < G.vexnum; v++)
		if (!visite[v])
			DFS(G, v);
	printf("\n");
}

typedef int QElemType; /* 队列类型 */

/* ------------------------------  单链队列--队列的链式存储结构   -----------------------------*/

typedef struct QNode
{
	QElemType data;
	struct QNode *next;
}QNode, *QueuePtr;

typedef struct
{
	QueuePtr front, rear; /* 队头、队尾指针 */
}LinkQueue;

/* ---------------------------------------------------------------------------------------------*/


/* ---------------------------------  需要用到的链队列的基本操作  --------------------------------*/

Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
	(*Q).front = (*Q).rear = (QueuePtr)malloc(sizeof(QNode));
	if (!(*Q).front)
		exit(OVERFLOW);
	(*Q).front->next = NULL;
	return OK;
}

Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
	if (Q.front == Q.rear)
		return TRUE;
	else
		return FALSE;
}

Status EnQueue(LinkQueue *Q, QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if (!p) /* 存储分配失败 */
		exit(OVERFLOW);
	p->data = e;
	p->next = NULL;
	(*Q).rear->next = p;
	(*Q).rear = p;
	return OK;
}

Status DeQueue(LinkQueue *Q, QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
	QueuePtr p;
	if ((*Q).front == (*Q).rear)
		return ERROR;
	p = (*Q).front->next;
	*e = p->data;
	(*Q).front->next = p->next;
	if ((*Q).rear == p)
		(*Q).rear = (*Q).front;
	free(p);
	return OK;
}


/* ------------------------------------------------------------------------------------------------*/


void BFSTraverse(AMLGraph G, Status(*Visit)(VertexType))
{ /* 初始条件: 图G存在,Visit是顶点的应用函数。算法7.6 */
  /* 操作结果: 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数 */
  /*           Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
  /*           使用辅助队列Q和访问标志数组visite */
	int v, u, w;
	VertexType w1, u1;
	LinkQueue Q;
	for (v = 0; v < G.vexnum; v++)
		visite[v] = FALSE; /* 置初值 */
	InitQueue(&Q); /* 置空的辅助队列Q */
	for (v = 0; v < G.vexnum; v++)
		if (!visite[v]) /* v尚未访问 */
		{
			visite[v] = TRUE; /* 设置访问标志为TRUE(已访问) */
			Visit(G.adjmulist[v].data);
			EnQueue(&Q, v); /* v入队列 */
			while (!QueueEmpty(Q)) /* 队列不空 */
			{
				DeQueue(&Q, &u); /* 队头元素出队并置为u */
				strcpy(u1, *GetVex(G, u));
				for (w = FirstAdjVex(G, u1); w >= 0; w = NextAdjVex(G, u1, strcpy(w1, *GetVex(G, w))))
					if (!visite[w]) /* w为u的尚未访问的邻接顶点的序号 */
					{
						visite[w] = TRUE;
						Visit(G.adjmulist[w].data);
						EnQueue(&Q, w);
					}
			}
		}
	printf("\n");
}

void MarkUnvizited(AMLGraph G)
{ /* 置边的访问标记为未被访问 */
	int i;
	EBox *p;
	for (i = 0; i < G.vexnum; i++)
	{
		p = G.adjmulist[i].firstedge;
		while (p)
		{
			p->mark = unvisited;
			if (p->ivex == i)
				p = p->ilink;
			else
				p = p->jlink;
		}
	}
}

void Display(AMLGraph G)
{ /* 输出无向图的邻接多重表G */
	int i;
	EBox *p;
	MarkUnvizited(G); /* 置边的访问标记为未被访问 */
	printf("%d个顶点:\n", G.vexnum);
	for (i = 0; i < G.vexnum; ++i)
		printf("%s ", G.adjmulist[i].data);
	printf("\n%d条边:\n", G.edgenum);
	for (i = 0; i < G.vexnum; i++)
	{
		p = G.adjmulist[i].firstedge;
		while (p)
			if (p->ivex == i) /* 边的i端与该顶点有关 */
			{
				if (!p->mark) /* 只输出一次 */
				{
					printf("%s-%s ", G.adjmulist[i].data, G.adjmulist[p->jvex].data);
					p->mark = visited;
					if (p->info) /* 输出附带信息 */
						printf("相关信息: %s ", p->info);
				}
				p = p->ilink;
			}
			else /* 边的j端与该顶点有关 */
			{
				if (!p->mark) /* 只输出一次 */
				{
					printf("%s-%s ", G.adjmulist[p->ivex].data, G.adjmulist[i].data);
					p->mark = visited;
					if (p->info) /* 输出附带信息 */
						printf("相关信息: %s ", p->info);
				}
				p = p->jlink;
			}
		printf("\n");
	}
}



/* --------------------------------------------------------------------------------------------------*/


 /* 主程序 */


Status visit(VertexType v)
{
	printf("%s ", v);
	return OK;
}

void main()
{
	int k, n;
	AMLGraph g;
	VertexType v1, v2;
	CreateGraph(&g);
	Display(g);
	printf("修改顶点的值,请输入原值 新值: ");
	scanf("%s%s", v1, v2);
	PutVex(&g, v1, v2);
	printf("插入新顶点,请输入顶点的值: ");
	scanf("%s", v1);
	InsertVex(&g, v1);
	printf("插入与新顶点有关的边,请输入边数: ");
	scanf("%d", &n);
	for (k = 0; k < n; k++)
	{
		printf("请输入另一顶点的值: ");
		scanf("%s", v2);
		InsertArc(&g, v1, v2);
	}
	Display(g);
	printf("深度优先搜索的结果:\n");
	DFSTraverse(g, visit);
	printf("广度优先搜索的结果:\n");
	BFSTraverse(g, visit);
	DestroyGraph(&g);
}

运行结果:

 
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、二叉树(二) 1. 写算法 (1)二叉树的直径定义为从根结点至叶子的最大路径长度。编写算法,求二叉树(二叉链表)的直径。 (2)已知二叉树(二叉链表)根结点指针bt,树中两个结点的指针p、q。编写算法求距离结点*p和*q最近的公共祖先的地址。 (3)已知二叉树(二叉链表)根结点指针bt,利用二叉树叶子结点的rchild指针域将所有叶子结点从左向右连接成一个单向链表。算法返回单向链表头结点指针(即最左边第1个叶子结点的地址)。 2. 编程题 (1) 从键盘输入一个字符串(要求字符串中无重复字符),将串中字符当做完全二叉树的顺序存储结构,建立对应的完全二叉树的二叉链表存储结构,输出先、中、后序遍历结果。 (2) 用先序遍历法建立二叉树二叉链表存储结构(结点数据域类型为char,输入字符序列用字符'#'表示NULL),实现中序线索化,并用非递归算法输出中序遍历结果的正序和逆序序列。 二、图 1. 已知某无向图如下图所示。画出该图的多重邻接表存储结构示意图。根据该存储结构,写出从顶点v0出发,深度和宽度优先遍历顶点访问次序。 2.写一个算法,判断无向图是否有环。算法提要:深度优先遍历过程中,访问某顶点后,该顶点的邻接点中有已访问的顶点且该已访问邻接点不是该顶点的上一级递归出发顶点(即存在回边),则有环。 3.编程题: 建立无向图邻接表存储结构,输出深度和宽度优先遍历顶点访问次序。 4.编程题:建立AOE网络存储结构,计算并输出ve[]和vl[]。 5.选作题*:算法设计-已知AOE网络的邻接表存储结构G,ve[]和vl[]值已全部求取,写出算法,输出所有关键路径。要求每条关键路径用源点至汇点的顶点序列(拓扑有序)表示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值