BUAA数据结构2023期末考试第三题

【问题描述】

某单位服务器集群网络结构呈树型结构,网络中节点可为交换机和服务器二种设备,服务器只能位于树的叶节点上。在该网络结构中正常工作的服务器每天定时向外广播心跳信息(即是否正在工作)(心跳技术,Heartbeat)。

编写一程序根据设备心跳记录日志分析是否存在运行故障设备,并报告可能存在的故障设备。心跳记录日志文件存储在根交换机,且根交换机不会出现故障,其中的每条记录只由服务器设备号(只要收到信息就表示状态正常)组成。诊断规则如下:

1)根交换机若没有收到某个服务器的心跳信息,但收到该服务器同属交换机下(不仅包括同层,也包括下面层)的服务器心跳信息,则诊断该服务器可能出错;例如下图中:若没有收到3号服务器的心跳信息,但收到6号服务器的心跳信息,则诊断3号服务器可能出错。

2)根交换机若没有收到某个交换机下(不仅包括同层,也包括下面层)的所有服务器心跳信息,则诊断该交换机可能出错(如果多个交换机满足条件,则只报最上层交换机故障)。例如下图中:若收到了15号服务器的心跳信息,但没有收到21号、22号和23号服务器的心跳信息,则只报13号交换机故障。

 test.png

                                               

【输入形式】

首先输入设备配置表中设备的数目,然后按如下格式分行输入设备配置表中每个设备的信息:

设备号(0-2000) 父设备(交换机)号 端口号(1-32) 设备类型(0表示交换机,1表示服务器)

上面设备信息数据间以一个空格分隔,输入的设备编号是无序的(但保证输入一个设备信息时,其父设备信息已经输入);

最后输入发出心跳的服务器号,以-1结束:

服务器号1 服务器号2 … -1(以一个空格分隔的服务器号序列,收到的心跳记录是无序的)。

注意:根设备肯定为交换机,没有父设备,其位于配置表的第一行,因此设备配置表的第一行一定为0 -1 -1 0。

【输出形式】

按前序遍历序输出可能出现故障的设备号,各数据间以一个空格分隔。前序遍历的原则为先访问根结点,然后根据端口号(从1至32)依次按照前序遍历的原则访问子树中的结点。

【样例输入】


37

0 -1 -1 0

4 0 5 0

5 4 2 1

7 4 8 0

29 4 10 1

13 7 16 0

15 7 26 1

14 13 1 0

23 13 2 1

21 14 2 1

22 14 5 1

27 14 8 0

8 0 32 0

16 8 27 0

17 16 2 0

28 16 5 0

30 16 7 0

18 17 5 1

31 28 3 0

33 30 3 1

32 31 2 1

34 31 8 1

35 31 12 0

36 35 15 1

1 0 1 0

2 1 2 0

3 1 3 1

9 2 1 0

6 2 9 1

10 9 2 0

12 9 3 0

19 9 5 1

11 10 3 1

20 12 2 0

24 12 5 1

25 20 2 0

26 20 5 1

18 32 36 21 22 5 23 6 3 -1

【样例输出】

9 27 15 29 34 30

【样例说明】

输入了37个设备的信息,构成了如上图所示的集群树型结构。根交换机收到了9个服务器发出的心跳记录。由于收到了6号服务器的心跳记录,但没有收到9号交换机下所有服务器的心跳信息,所以判定9号交换机可能故障,其下的所有设备不再报故障;由于收到了23号服务器的心跳记录,说明7号交换机没有故障,但没收到其下的15号服务器的心跳信息,所以可判定15号服务器可能故障;其它判定类似......。

【评分标准】

该要求查找可能出现故障的设备,提交程序名为beat.c。

【思路】
收录一位佬的代码
 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 2048

typedef struct Node {
	int id;
	int type;
	int fa_id;
	int height;//dfs序深度
	int deep;//bfs序深度
	int rank;//接在父节点的几号子树上
	struct Node* ch[8], * fa;
}Node;

int n, tar_id;

Node* getNewNode(int id, int type)
{
	Node* p = (Node*)malloc(sizeof(Node));
	p->type = type;
	p->id = id;
	p->fa_id = 0;
	p->rank = 0;
	p->deep = 0;
	p->height = 0;
	for (int i = 0;i < 8;i++)
	{
		p->ch[i] = NULL;
	}
	p->fa = NULL;
	return p;
}

void insert(Node* root, Node* tar)
{
	if (root->id == tar->fa_id)
	{
		root->ch[tar->rank] = tar;
		tar->fa = root;//建立回溯线索
		return;
	}
	for (int i = 0;i < 8;i++)
	{
		if (root->ch[i] != NULL)
		{
			insert(root->ch[i], tar);
		}
	}
	return;
}
//节点dfs序深度标记
int k = 0;
void dfs(Node* root)
{
	root->height = k++;
	for (int i = 0;i < 8;i++)
	{
		if (root->ch[i] != NULL)
		{
			dfs(root->ch[i]);
		}
	}
	return;
}


//带回溯指针的树的遍历相当于图的遍历,需要搜索去重,防止重复搜索某个节点
Node* ans[1005];//存储得到的打印机序
int cnt;
int vis[1005];//地图不能重复遍历

Node* que[1005];
int head, tail;
void bfs(Node* root)//这里把sig节点看成树的根节点,相当于对树进行翻转
{
	que[tail++] = root;
	while (head < tail)
	{
		Node* tmp = que[head++];
		if (tmp->type == 2)
		{
			ans[cnt++] = tmp;
		}
		//只有0号是转换器,可以向孩子节点转移,
		if (tmp->type == 0)
		{
			for (int i = 0;i < 8;i++)
			{
				if (tmp->ch[i] != NULL && vis[tmp->ch[i]->id] == 0)
				{
					vis[tmp->ch[i]->id] = 1;//标记访问
					que[tail] = tmp->ch[i];
					que[tail]->deep = tmp->deep + 1;
					tail++;
				}
			}
		}
		//所有节点都可以向父节点转移
		if (tmp->fa != NULL && vis[tmp->fa->id] == 0)
		{
			vis[tmp->fa->id] = 1;
			que[tail] = tmp->fa;
			que[tail]->deep = tmp->deep + 1;
			tail++;
		}
	}
	return;
}
int main()
{
	int r;
	Node* sig = NULL;//指向目标计算机编号的节点
	scanf("%d",&r);
	int id = 0, type = 0, fa = 0, rank = 0;
	scanf("%d %d %d %d", &id, &fa, &type, &rank);
	Node* root = getNewNode(id, type);
	for (int i = 0;i < n-1;i++)
	{
		scanf("%d %d %d %d", &id, &fa, &type, &rank);
		Node* tar = getNewNode(id, type);
		tar->fa_id = fa;
		tar->rank = rank;
		if (id == tar_id)sig = tar;
		insert(root, tar);
	}
	int numset[200];
	int y=1;
	int u=0;
	while(y)
	{
		scanf("%d",numset[u++]);
		if(numset[u-1]==-1)
		{
			y=0;
		}
	}
	
	
	return 0;
}



 

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值