数据结构与算法之并查集基础知识

一个开源的个人学习计算机科学知识成长记录(前后端,数据结构与算法)

并查集

并查集主要用于解决元素分组问题,它支持对不相交的几何操作,主要是以下两种操作:

合并(Union) 合并两个不相交的集合

**查询(Find)**查询两个元素是否在同一个集合中

图结构

初始化

假如有编号为1, 2, 3, …, n的n个元素,我们用一个数组fa[]来存储每个元素的父节点(因为每个元素有且只有一个父节点,所以这是可行的)。一开始,我们先将它们的父节点设为自己。

const init = function(n){
    const fa = [];
    for(let i=1;i<=n;i++){
        fa[i] = i;
    }
}

查询

用递归的写法实现对代表元素的查询:一层一层访问父节点,直至根节点(根节点的标志就是父节点是本身)。要判断两个元素是否属于同一个集合,只需要看它们的根节点是否相同即可。

const find = funtion(fa,x){
    if(fa[x] == x){
        return x;
    }else{
        return  find(fa[x]);
    }
}

合并

合并操作先找到两个集合的代表元素,然后将前者的父节点设为后者即可。当然也可以将后者的父节点设为前者,这里暂时不重要。本文末尾会给出一个更合理的比较方法。

const union = fucntion(i,j){
    fa[find[i]] = find[j]
}

路径压缩

使用路径压缩的方法。既然我们只关心一个元素对应的根节点,那我们希望每个元素到根节点的路径尽可能短,最好只需要一步

在查询的过程中,把沿途的每个节点的父节点都设为根节点即可。下一次再查询时,直接返回父节点即可

const find = function(fa,x){
    if(x == fa(x)){
        return x;
    }else{
        fa[x]=find([fa[x]]); // 设父节点为根节点
        return fa[x]; // 返回父节点
    }
}

// 简化写法

const find = function(fa,x){
    return x == fa[x]?x:(fa[x]=find(fa[x])); // 记得加括号
}

按秩合并

我们应该把简单的树往复杂的树上合并,而不是相反。因为这样合并后,到根节点距离变长的节点个数比较少

// 初始化
const init = function(n){
    const fa = [];
    const rank = [];
    for(let i=1;i<=n;i++){
        fa[i] = i;
        rank[i] =1;
    }
}
// 合并
const merge = function(fa,rank,i,j){
    const x = find(fa,i); //先找到两个根节点
    const y = find(fa,j);
    if(rank[x]<=rank[y]){
        fa[x]=y;
    }else{
        fa[y]=x;
    }
    if(rank[x]==rank[y]&&x!=y){
        rank[y]++; //如果深度相同且根节点不同,则新的根节点的深度+1
    }
}

P1551 亲戚问题

题目背景
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
题目描述
规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
输入格式
第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。
以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Mi和Mj具有亲戚关系。
接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。
输出格式
P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。

const readline = require('readline');  
const rl = readline.createInterface({  
    input: process.stdin,  
    output: process.stdout  
});

rl.on('close', function() {  
    console.log('程序结束');  
    process.exit(0);  
}); 

const readSingle = function(){
        const inputAr = [];
        rl.on('line', function (input) {  
            inputArr = input.split(" ");  
            rl.close();  
       }); 
       return inputArr;
}

const sibling =function(n,m,p,x,y){
    const fa = [];
    const rank = [];
    init(fa,rank,n);
    
    for(let i=0;i<m;++i){
        // 读取两个参数
        const read = readSingle();
        const  left = read[0];
        const right = read[1];
        merge(fa,rank,left,right);
    }
    
    for(let i=0;i<p:++i){
        // 读取两个参数
        const read = readSingle();
        const  left = read[0];
        const right = read[1];
        console.log(find(fa,left)==find(fa,right)?"Yes":"No")
    }
}
/**
* init
*/
const init = function(fa,rank,n){
    for(let i=0;i<=n;i++){
        fa[i] = i;
        rank[i] = 1;
    }
}
/**
*
*/
const  find = function(fa,x){
    return x == fa[x]?x:(fa[x]=find(fa[x]));
}
/*
* 将秩小的挂载到秩大的数值上
*/
const merge = function(fa,rank,i,j){
    const x = find(fa,i);
    const y = find(fa,j);
    if(rank[x]<=rank[y]){
        fa[x] = y;
    }else{
        fa[y] = x;
    }
    if(rank[x]==rank[y]&&x!=y){
        rank[y]++;
    }
}

总结

遇到并查集的时候,要初始化并查集,建立合并和查找的三个函数

参考

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 学习数据结构和算法通常需要以下几步: 1. 了解基本的编程知识,包括变量、条件语句、循环、函数等。 2. 学习基本的数据结构,如数组、链表、栈、队列、树等。 3. 学习常见的算法,如排序、搜索、图论等。 4. 多做题,熟练掌握数据结构和算法的应用。 5. 学习进阶的数据结构和算法,如哈希表、并查集、最短路等。 可以通过读书、看视频、做题等方式来学习数据结构和算法。有很多优秀的书籍和在线课程可以帮助你学习。 ### 回答2: 数据结构与算法是计算机科学中非常重要的基础知识,学习好这门课程对于提高编程能力和解决实际问题至关重要。以下是我对于如何学习数据结构与算法的建议。 第一,理解基本概念。首先要理解数据结构和算法的基本概念,例如数组、链表、栈、队列等数据结构,以及排序、查找、递归、动态规划等算法。可以通过阅读相关教材、参考书籍或者在线教程来学习这些概念,并进行实践。 第二,掌握基本操作。在了解了基本概念之后,需要掌握数据结构与算法的基本操作。这包括插入、删除、查找等操作,以及排序、查找等算法的具体实现方法。可以通过编写代码来实践这些操作,并进行调试和优化。 第三,解决问题。学习数据结构与算法的最终目的是解决实际问题。可以选择一些经典的问题,例如查找算法中的二分查找、排序算法中的快速排序等,通过分析问题的特点和要求,选择合适的数据结构和算法来解决,并进行实现和测试。 第四,练习和总结。学习数据结构与算法需要不断地进行练习和总结。可以选择一些习题进行练习,挑战自己的编程能力。同时,及时总结和归纳所学到的知识和经验,将这些知识内化为自己的思维方式和工作习惯。 最后,不断学习和提高。数据结构与算法是一门广阔而深奥的学科,需要不断学习和提高自己的知识水平。可以参与相关的讨论和学习交流,阅读更深入的研究和应用资料,参与项目实践以提升自己的能力和经验。 总之,数据结构与算法是一门需要深入理解和不断实践的学科。通过理解基本概念、掌握基本操作、解决实际问题、练习和总结,以及持续学习和提高,可以逐渐掌握和应用好这门课程的知识。 ### 回答3: 学习数据结构与算法是程序员必备的基本功,以下是一些建议。 首先,了解数据结构的概念和基本的数据结构类型,如数组、链表、栈、队列、树、图等。掌握它们的定义、特点和基本操作。 其次,学习算法的基本思想和常用的算法技巧,如递归、分治、贪心、动态规划等。了解它们的应用场景和解决问题的思路。 然后,通过学习经典的数据结构与算法的实现代码来加深理解。可以通过书籍、在线教程、视频课程等多种途径进行学习,找到适合自己的学习资源。 接着,通过刷题来提升自己的实践能力。可以选择一些在线刷题平台,如LeetCode、LintCode等,挑选一些经典的算法问题进行解答。在实践中不断思考和总结,逐渐掌握解决问题的套路和算法的优化思路。 此外,参与算法竞赛和交流也是一个不错的学习方式。可以参加一些算法竞赛平台的比赛,与其他程序员进行交流和学习。也可以参加一些线下的技术交流活动,与其他程序员面对面地讨论和学习。 最后,持续学习和实践是关键。数据结构与算法是一个广阔的领域,需要不断学习,不断实践,不断总结经验。在实际的项目中尽量应用所学的数据结构与算法,提升自己的编程能力。 总之,学习数据结构与算法需要理论与实践相结合,要有积极的学习态度和持之以恒的学习精神。只有不断努力,才能在数据结构与算法的学习中取得进步。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值