《啊哈,算法》-19-数据结构-并查集-C语言实现-情景化案例学习算法和数据结构

63 篇文章 4 订阅
31 篇文章 2 订阅

一、问题描述

目前有一些强盗,警察在破案的过程中想知道一共有几个犯罪团伙。
可以根据线索进行份分析:
现在有10个强盗,给他们编号为1到10.
1和2是同伙;
3和4是同伙;
5和2是同伙;
4和6是同伙;
2和6是同伙;
8和7是同伙;
9和7是同伙;
1和6是同伙;
2和4是同伙。
有一点需要注意,强盗同伙的同伙也是同伙。

二、问题分析

首先我们假设10个强盗是互相不认识的,一个就是一个团伙,接下来根据线索进行归队过程。
第一步:申请一个一维数组,用数组下标1-10表示10个强盗,用下边对应的表格表示他们是属于哪个团伙的。
第二步:初始化,10个强盗每个都是一个团伙。
在这里插入图片描述
第三步:合并同伙,如果发现两个强盗是同伙,他们就是属于一个犯罪团伙。

根据“靠左法则”和“擒贼先擒王法则“””那么就得到最后的结果(这个过程如果不理解的话可以自己在纸上画一遍):
团伙1:1,2,3,4,5,6
团伙2:7,8,9
团伙3:10
因此有三个独立的犯罪团伙。

三、代码复现

//并查集
#include<stdio.h>
int f[1000]={0},n,m,k,sum=0;
//这里是重要的初始化,数组里边存的是自己数组下标的编号就好了
void init()
{
	int i;
	for(i=1;i<=n;i++)
		f[i]=i;
 } 
 
 //这里是找爹的递归函数, 不停的去找爹,直到找到祖宗为止,其实就是去找犯罪团伙的最高领导人,“擒贼先擒王”原则
 int getf(int v)
 {
 	if(f[v]==v)
 		return v;
 	else
 	{
 		//这里是路径压缩,每次在函数返回的时候,顺带把路上的人的boss改为找到的祖宗的编号,也就是犯罪团伙人最高领导人的编号
		//这样可以提高今后找犯罪团伙人的最高领导人,其实就是树的祖先的速度
		f[v]=getf(f[v]);
		return f[v]; 
	 
	 }
  } 
  
  
//这里是合并两个子集合的函数
void merge(int v,int u)
{
	int t1,t2;
	t1=getf(v);
	t2=getf(u);
	if(t1!=t2)//判断两个结点是否在同一个集合中,是否是同一个祖先 
	{
		f[t2]=t1;
		//靠左原则,左边变成右边的boss,即把右边的集合,作为左边集合的子集合
		//经过路径压缩后,将f[u]的根的值也赋值为v的祖先f[t1].	
	}
 } 
 
//主函数
int main() 
 {
 	int i,x,y;
 	scanf("%d %d",&n,&m);
 	
 	//必须的初始化
	 init();
	 for(i=1;i<=m;i++)
	 {
	 	//开始合并犯罪团伙
		 scanf("%d %d",&x,&y) ;
		 merge(x,y);
	 }
	 
	 //最后扫描有多少个独立的犯罪团伙
	 for(i=1;i<=n;i++)
	 {
	 	if(f[i]==i)
	 		sum++;
	  } 
	  getchar();
	  getchar();
	  printf("%d\n",sum);
	  return 0;
 }
 
 

在这里插入图片描述

四、总结

并查集通过一个一维数组来实现,其本质就是维护一个森林。
刚开始的时候 ,森林中的每个点都是孤立的,也可以理解为一个点就是一棵树。
之后通过一些条件,主键合并为一棵大树。
其实合并的过程就是“认爹”的过程,在这个过程中,要遵守“靠左法则”和“擒贼先擒王”的法则。
在每次判断两个结点寿佛已经子同一棵树中的时候(一棵树其实就是一个集合),也要注意必须求其根源,中间父亲结点是不能说明问题的,必须找到其祖宗,判断两个结点的祖宗是否在同一个根节点才行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单链表是一种常见的数据结构,它由一个或多个节点组成,每个节点包含一个数据域和一个指针域,指针域指向下一个节点。 实现单链表的查找位序算法函数需要以下步骤: 1. 定义一个指针p指向链表的头节点,并定义一个变量count,用于计数。 2. 从头节点开始,遍历链表,当p指向某个节点时,计数器count加1。 3. 如果p指向的节点的数据与目标数据相等,则返回当前的计数器count,即为目标数据的位序。 4. 如果p指向的节点不是目标数据,则将p指向下一个节点,重复步骤3。 5. 如果遍历完链表后仍未找到目标数据,则返回-1,表示未找到。 下面是C语言实现单链表查找位序算法函数的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义单链表节点结构 typedef struct Node { int data; // 数据域 struct Node* next; // 指针域 } Node; // 查找位序的算法函数 int findPosition(Node* head, int target) { Node* p = head; // 指向头节点 int count = 0; // 计数器初始为0 while (p != NULL) { count++; // 计数器加1 if (p->data == target) { return count; // 找到目标数据,返回当前计数器的值 } p = p->next; // 指向下一个节点 } return -1; // 遍历完链表未找到目标数据,返回-1 } int main() { // 创建链表 Node* head = (Node*)malloc(sizeof(Node)); head->data = 1; // 头节点数据为1 Node* node1 = (Node*)malloc(sizeof(Node)); node1->data = 2; Node* node2 = (Node*)malloc(sizeof(Node)); node2->data = 3; head->next = node1; node1->next = node2; node2->next = NULL; // 查找位序示例 int target = 3; // 目标数据为3 int position = findPosition(head, target); if (position != -1) { printf("目标数据 %d 的位序为 %d\n", target, position); } else { printf("未找到目标数据 %d\n", target); } // 释放链表内存 free(node2); free(node1); free(head); return 0; } ``` 在上述代码中,我们首先定义了一个指向头节点的指针p和一个计数器count,然后使用while循环遍历链表。当p指向某个节点时,计数器加1,并判断该节点的数据是否与目标数据相等。如果找到了目标数据,则返回当前计数器的值,即为目标数据的位序。如果遍历完链表仍未找到目标数据,则返回-1表示未找到。最后在主函数中演示了调用该算法函数的示例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值