第九章第十三节(无向图求欧拉回路)

欧拉环游:在图中找到一条路径,从起点开始,依此经过图中的所有边,一个边只能走一次,到达终点,终点和起点可以不同

欧拉回路:在图中找到一条路径,从起点开始,依此经过图中的所有边,最后回到起点,一个边只能走一次。

欧拉环游存在的条件:当前图是连通的,图中的恰有零个或两个顶点的度是奇数,其余顶点的度数为偶数,才会存在

欧拉回路存在的条件:当前图是连通的,图中所有的顶点的度是偶数时,欧拉回路必存在。

寻找欧拉回路的算法:如果从起点出发的所有边均已用完,那么图中就会有的部分遍历不到。最容易补救的方法就是找出有尚未访问的边的路径上的第一个顶点,并执行另外一次深度优先搜索。这将给出另外一个回路,把它拼接到原来的回路上。
继续该过程直到所有的边都被遍历到为止。

用到的数据结构

typedef struct Node* ptrNode;
struct Node {
	int v;				//记录顶点		
	ptrNode next;		
};
//用链表来存储欧拉回路走过的路径,head为链表的头节点
ptrNode head = (ptrNode)malloc(sizeof(struct Node));
ptrNode H = head;

//首先判断图是否为连通的,然后判断图中顶点的度是否都为偶数
int Viseted[MAXVERTEX];			//用一次dfs,记录图是否连通
int degree[MAXVERTEX];			//记录每个顶点的度
int ne;							//ne记录走过的边
Graph P;						//邻接矩阵存储图

主函数步骤

int main() {
	P = BuildGraph();			//初始化图
	if (IsConnect()) {			//IsConnect 函数判断图是否连通
		if (Isdegree()) {		//Isdegree 函数判断每个顶点的度是否为偶数
			printf("存在欧拉回路\n");
			isDfs(0);			//如果存在欧拉回路,从顶点0开始寻找欧拉回路
		}
		else {
			printf("图中节点的度数不为偶数,欧拉回路不存在\n");
		}
	}
	else {
		printf("该图不连通,无欧拉回路\n");
	}
	return 0;
}

判断图是否连通函数

void dfs(int vertex) {		//对图进行一次dfs,判断图是否连通
	Viseted[vertex] = 1;
	for (int i = 0; i < P->Nv; i++) {
		if (P->Graph[vertex][i] != 0 && Viseted[i] == 0) {
			dfs(i);
		}
	}
}
bool IsConnect() {
	dfs(0);				//进行一次dfs,然后判断,每个顶点是否都已访问到	
	for (int i = 0; i < P->Nv; i++) {
		if (Viseted[i] == 0)		
			return false;
	}
	return true;
}

判断图中顶点度的个数是否为偶数

bool Isdegree() {
	//判断图中各个顶点的度是否为偶数
	for (int i = 0; i < P->Nv; i++) {
		for (int j = 0; j < P->Nv; j++) {
			if (P->Graph[i][j] != 0) {
				//i到j有一条边。
				degree[j]++;
			}
		}
	}
	for (int i = 0; i < P->Nv;i++) {
		if (degree[i] % 2 != 0) {
			return false;
		}
	}
	return true;
}

求欧拉回路函数

void Dfs(int vertex) {
	//将走过的顶点,加入链表
	ptrNode p = (ptrNode)malloc(sizeof(struct Node));
	p->v = vertex;
	p->next = NULL;
	H->next = p;
	H = p;
	for (int i = 0; i < P->Nv; i++) {
		if (P->Graph[vertex][i] != 0) {
			P->Graph[vertex][i] = 0;	//将边删除
			P->Graph[i][vertex] = 0;	//将边删除
			ne += 2;					//统计当前走过的边数
			Dfs(i);						
			break;						//每个顶点不能往后再走
		}
	}
}
void euler(int vertex) {
	//求欧拉回路路径
	Dfs(vertex);
	int flag;
	ptrNode p,tmp,f=NULL;
	while (ne < P->Ne * 2) {
		for (p = head->next; p; p = p->next) {
			//找出从路径开始的第一个尚未走过边的顶点
			flag = 0;
			for (int i = 0; i < P->Nv; i++) {
				if (P->Graph[p->v][i] != 0) {
					//顶点p->v有边尚未走过
					f = H;			//记录当前链表尾的位置	
					flag = 1;		//找到尚未走过的边的顶点
					Dfs(p->v);		//p->v进行一次dfs
					break;
				}
			}
			if (flag == 1)
				break;
		}
		//此时f->next为从p->v顶点开始走过的路径
		//p为链表中要拼接的位置
		tmp = f;
		f = f->next->next;
		//将f拼接到p后面
		tmp->next = NULL;		//将链表尾置位空
		H = tmp;				//H为新拼接后的链表尾
		tmp = p->next;			//保存p->next
		p->next = f;		
		while (p->next)
			p = p->next;
		p->next = tmp;			//将tmp接回p->next
	}
	//输出欧拉回路
	for (p = head->next; p;p = p->next) {
		printf("%d ", p->v);
	}
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值