MOOC数据结构课程 题集15 列出连通集

06-图1 列出连通集 (25 分)

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:

输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

输出格式:

按照"{ v​1​​ v​2​​ ... v​k​​ }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

输入样例:

8 6
0 7
0 1
2 0
4 1
2 4
3 5

输出样例:

{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }

最后输出要求一直没看懂,后来才知道原来是要给临接表的每一个表头节点后面的临接点排序。

感觉这题用临接矩阵会舒服一些,临接表纯粹是为了学习使用的 

#include <iostream>
#include <deque>
#define Vertex int
#define Edge ENode
#define MAX_VERTEX 10

typedef struct _ENode	//边
{
	Vertex V1;
	Vertex V2;
}ENode;

typedef struct _AdjVNode//临接顶点
{
	Vertex AdjV;
	_AdjVNode *next;
}AdjVNode;

typedef struct _VNode	//顶点表头
{
	AdjVNode *first_node;
}VNode[MAX_VERTEX];

typedef struct _Graph	//图
{
	int Vertex_num;
	int Edge_num;
	VNode G;
}Graph;

void creat_Graph(Graph *G, int Vnum, int Enum);
void insert_Edge(Graph *, Edge);
void BFS_components(Graph *);
void BFS(Graph *, Vertex first_V, int visited[]);
void DFS_components(Graph *);
void DFS(Graph *, Vertex first_V, int visited[]);
void print_squ();
void sort_AdjV(Graph *);
void sort_bubble(AdjVNode *);

using namespace std;

deque<Vertex> V_squ;//输出的序列
bool is_first_print = 1;

int main()
{
	int N, E;
	cin >> N >> E;
	Graph *graph = new Graph;
	Edge edge;
	creat_Graph(graph, N, E);
	for (int i = 0; i < E; i++)
	{
		cin >> edge.V1 >> edge.V2;
		insert_Edge(graph, edge);
	}
	sort_AdjV(graph);
	DFS_components(graph);
	BFS_components(graph);

	return 0;
}

void creat_Graph(Graph *graph, int Vnum, int Enum)
{
	graph->Vertex_num = Vnum;
	graph->Edge_num = Enum;
	for (Vertex i = 0; i < graph->Vertex_num; i++)
		graph->G[i].first_node = NULL;
}

void insert_Edge(Graph *graph, Edge edge)
{ 
	AdjVNode *AdjV_1, *AdjV_2;
	AdjV_1 = new AdjVNode;
	AdjV_2 = new AdjVNode;
	AdjV_1->AdjV = edge.V1;
	AdjV_2->AdjV = edge.V2;
	//头插法
	AdjV_2->next = graph->G[edge.V1].first_node;
	graph->G[edge.V1].first_node = AdjV_2;
	AdjV_1->next = graph->G[edge.V2].first_node;
	graph->G[edge.V2].first_node = AdjV_1;
}

//广度优先遍历(输出)所有连通分量
void BFS_components(Graph *graph)
{
	int	visited[MAX_VERTEX];
	for (int i = 0; i < graph->Vertex_num; i++)
		visited[i] = 0;

	for (Vertex i = 0; i < graph->Vertex_num; i++)
		if (visited[i] == 0) {
			BFS(graph, i, visited);
			print_squ();
			V_squ.clear();
		}
}

void BFS(Graph *graph, Vertex first_V, int visited[])	//入队前访问,出队后检查临接点并入队
{														//直接访问临接表中的节点,访问完入队,之后只要检查他的临界点就OK了,不要单独去访问表头节点
	AdjVNode *last;										//不用另外再写一个访问表头的代码,所以更加简洁,唯一一次访问表头是在开头的时候
	Vertex V = first_V;
	deque<Vertex>visit_queue;
	V_squ.push_back(V);//访问表头
	visited[V] = 1;
	visit_queue.push_back(V);
	while (!visit_queue.empty())
	{
		V = visit_queue.front();
		visit_queue.pop_front();
		last = graph->G[V].first_node;
		while (last != NULL) {//将表头的所有临接点访问完,并入队,之后就不用访问表头了,出队后只要访问临接即可
			if (visited[last->AdjV] == 0) {
				V_squ.push_back(last->AdjV);
				visited[last->AdjV] = 1;
				visit_queue.push_back(last->AdjV);
			}
			last = last->next;
		}
	}
}

//深度优先遍历(输出)所有连通分量
void DFS_components(Graph *graph)
{
	int	visited[MAX_VERTEX];
	for (int i = 0; i < graph->Vertex_num; i++)
		visited[i] = 0;

	for (Vertex i = 0; i < graph->Vertex_num; i++)
		if (visited[i] == 0) {
			DFS(graph, i, visited);
			print_squ();
			V_squ.clear();
		}
}

void DFS(Graph *graph, Vertex first_V, int visited[])
{
	AdjVNode *last;
	Vertex V = first_V;

	if (visited[V] == 0)
	{
		V_squ.push_back(V);
		visited[V] = 1;
	}
	else return;
	last = graph->G[V].first_node;
	while (last != NULL)
	{
		V = last->AdjV;
		DFS(graph, V, visited);
		last = last->next;
	}
}

void print_squ()
{
	if (is_first_print)
		is_first_print = 0;
	else
		cout << endl;
	cout << "{ ";
	while (!V_squ.empty())
	{
		cout << V_squ.front() << " ";
		V_squ.pop_front();
	}
	cout << "}" ;
}

void sort_AdjV(Graph *graph)
{
	AdjVNode *p;
	for (Vertex i = 0; i < graph->Vertex_num; i++)
	{
		p = graph->G[i].first_node;
		if (p) sort_bubble(p);
	}
}

void sort_bubble(AdjVNode *head)
{
	AdjVNode *p,*q;
	AdjVNode *last;
	last = NULL;
	Vertex tmp;
	while (head->next != last)
	{
		p = head;
		q = p->next;
		while (p->next != last)
		{
			if (p->AdjV > q->AdjV)
			{
				tmp = p->AdjV;
				p->AdjV = q->AdjV;
				q->AdjV = tmp;
			}
			p = p->next;
			q = q->next;
		}
		last = p;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值