一、有序集合求交集的方法有

a)二重for循环法,时间复杂度O(n*n)

b)拉链法,时间复杂度O(n)

c)水平分桶,多线程并行

d)bitmap,大大提高运算并行度,时间复杂度O(n)

e)跳表,时间复杂度为O(log(n))

以下是方法的具体介绍:

方案一:for * for,土办法,时间复杂度O(n*n)

    每个搜索词命中的网页是很多的,O(n*n)的复杂度是明显不能接受的。倒排索引是在创建之初可以进行排序预处理,问题转化成两个有序的list求交集,就方便多了。

方案二:有序list求交集,拉链法

    

      有序集合1{1,3,5,7,8,9}

      有序集合2{2,3,4,5,6,7}

    两个指针指向首元素,比较元素的大小:

    (1)如果相同,放入结果集,随意移动一个指针

    (2)否则,移动值较小的一个指针,直到队尾

  这种方法的好处是:

  (1)集合中的元素最多被比较一次,时间复杂度为O(n)

  (2)多个有序集合可以同时进行,这适用于多个分词的item求url_id交集

  这个方法就像一条拉链的两边齿轮,一一比对就像拉链,故称为拉链法

方案三:分桶并行优化

    数据量大时,url_id分桶水平切分+并行运算是一种常见的优化方法,如果能将list1<url_id>和list2<url_id>分成若干个桶区间,每个区间利用多线程并行求交集,各个线程结果集的并集,作为最终的结果集,能够大大的减少执行时间。

    举例:

      有序集合1{1,3,5,7,8,9, 10,30,50,70,80,90}

      有序集合2{2,3,4,5,6,7, 20,30,40,50,60,70}

    求交集,先进行分桶拆分:

      桶1的范围为[1, 9]

      桶2的范围为[10, 100]

      桶3的范围为[101, max_int]

    于是:

    集合1就拆分成

    集合a{1,3,5,7,8,9}

    集合b{10,30,50,70,80,90}

    集合c{}

    集合2就拆分成

    集合d{2,3,4,5,6,7}

    集合e{20,30,40,50,60,70}

    集合e{}

    每个桶内的数据量大大降低了,并且每个桶内没有重复元素,可以利用多线程并行计算:

    桶1内的集合a和集合d的交集是x{3,5,7}

    桶2内的集合b和集合e的交集是y{30, 50, 70}

    桶3内的集合c和集合d的交集是z{}

   最终,集合1和集合2的交集,是x与y与z的并集,即集合{3,5,7,30,50,70}

方案四:bitmap再次优化

    数据进行了水平分桶拆分之后,每个桶内的数据一定处于一个范围之内,如果集合符合这个特点,就可以使用bitmap来表示集合:

      

  如上图,假设set1{1,3,5,7,8,9}和set2{2,3,4,5,6,7}的所有元素都在桶值[1, 16]的范围之内,可以用16个bit来描述这两个集合,原集合中的元素x,在这个16bitmap中的第x个bit为1,此时两个bitmap求交集,只需要将两个bitmap进行“与”操作,结果集bitmap的3,5,7位是1,表明原集合的交集为{3,5,7}

    水平分桶,bitmap优化之后,能极大提高求交集的效率,但时间复杂度仍旧是O(n)

    但bitmap需要大量连续空间,占用内存较大

方案五:跳表skiplist

    有序链表集合求交集,跳表是最常用的数据结构,它可以将有序集合求交集的复杂度由O(n)降至O(log(n))

     

    集合1{1,2,3,4,20,21,22,23,50,60,70}

    集合2{50,70}

    要求交集,如果用拉链法,会发现1,2,3,4,20,21,22,23都要被无效遍历一次,每个元素都要被比对,时间复杂度为O(n),能不能每次比对“跳过一些元素”呢?

跳表就出现了:

      

    集合1{1,2,3,4,20,21,22,23,50,60,70}建立跳表时,一级只有{1,20,50}三个元素,二级与普通链表相同,集合2{50,70}由于元素较少,只建立了一级普通链表;如此这般,在实施“拉链”求交集的过程中,set1的指针能够由1跳到20再跳到50,中间能够跳过很多元素,无需进行一一比对,跳表求交集的时间复杂度近似O(log(n)),这是搜索引擎中常见的算法。

参考:list1与list2求交集的方法总结!

list1与list2求交集的方法总结!的更多相关文章

  1. 【转载】C#编程中两个List集合使用Intersect方法求交集

    在C#语言程序设计中,List集合是常用的集合数据类型,在涉及集合类型的运算中,有时候我们需要计算2个List集合中共有的数据,即对2个List集合求交集运算.此时可以使用C#语言提供的Interse ...

  2. python list求交集

    方法一: a=[1,2,3] b=[1,3,4] c=list(set(a).intersection(set(b))) print c #[1,3] 这种方法是先把list转换为set,再用set求 ...

  3. for循环求交集

    for循环方式求交集 #!/usr/bin/env python #coding:utf-8 #取交集 #定义两个序列对象,求alist与blist对象的交集元素 alist = [2,9,3,4,5 ...

  4. javascript集合求交集

    两集合求交集 思路: 1. 每一次从B数组中取一值,然后在A数组里逐个比较,如果有相等的,则保存.该算法复杂度为 O(MN). M, N 分别为数组 A B 的长度. 2. 因为A B 都排过序,所以 ...

  5. python 两个list 求交集,并集,差集

    def diff(listA,listB): #求交集的两种方式 retA = [i for i in listA if i in listB] retB = list(set(listA).inte ...

  6. .net找List1和List2的差集

    有个需求是找两个自定义类泛型集合的差集: class Person { public string Name{get; set;} public string Country{get; set;} } ...

  7. Redis实现求交集操作结果缓存的设计方案

    Redis的集合操作 实话说,Redis提供的集合操作是我选择它成为内存数据库的一个主要理由,它弥补了传统关系型数据库在这方面带来的复杂度,使得只需要简单的一个命令就可以完成一个复杂SQL任务,并且交 ...

  8. java(List或Array数组)求交集、并集、差集, 泛型工具类

    业务需要求不同类型的交集.并集.差集为避免代码冗余编写工具类. 注:list 转数组需传入数组,如果将原数组传入将会改变原数组的值,同时泛型数组又不可以实例化,解决方案:Arrays.copyOf(n ...

  9. PHP实现 bitmap 位图排序 求交集

    2014年12月16日 17:15:09 初始化一串全为0的二进制; 现有一串无序的整数数组; 如果整数x在这个整数数组当中,就将二进制串的第x位置为1; 然后顺序读取这个二进制串,并将为1的位转换成 ...

随机推荐

  1. Oracle 11g rac 添加新节点测试

    [转]https://blog.csdn.net/shiyu1157758655/article/details/60877076 前期准备: 操作系统设置OS版本必须相同,检查内核参数,系统内存.C ...

  2. maven 仓库配置 pom中repositories属性

    文章转自http://blog.csdn.net/zlgydx/article/details/51130627 什么是Maven仓库在不用Maven的时候,比如说以前我们用Ant构建项目,在项目目录 ...

  3. mysql 存儲emjoy表情是報錯Incorrect string value:

    解决方法: [mysqld] character-set-client-handshake=FALSE character-set-server=utf8mb4 collation-server=ut ...

  4. PAT A1121 Damn Single (25 分)——set遍历

    "Damn Single (单身狗)" is the Chinese nickname for someone who is being single. You are suppo ...

  5. DRF跨域,简单请求和复杂请求

    跨域就是跨域名,跨端口 - 为什么会有跨域? 浏览器有同源限制策略 - 绕过浏览器同源策略就可以跨域 -  方式一: jsonp(利用浏览器特性) 在html动态创建script标签 同源策略会阻止a ...

  6. 【Codeforces Round 1132】Educational Round 61

    Codeforces Round 1132 这场比赛做了\(A\).\(B\).\(C\).\(F\)四题,排名\(89\). \(A\)题\(wa\)了一次,少考虑了一种情况 \(D\)题最后做出来 ...

  7. JavaScript设计模式 - 策略模式(表单验证)

    表单提交的时候,总是要校验,不同的表单可能校验相同的功能. 为了避免代码重复的复制黏贴,使用策略模式,写出来的代码赏心悦目,且可扩展,还可以作为插件到处使用 <!DOCTYPE html> ...

  8. Luogu2993 FJOI2014 最短路径树问题 最短路树、长链剖分

    传送门 强行二合一最为致命 第一问直接最短路+$DFS$解决 考虑第二问,与深度相关,可以考虑长链剖分. 设$f_{i,j}$表示长度为$i$,经过边数为$j$时的最大边权和,考虑到每一次从重儿子转移 ...

  9. 锁、C#中Monitor和Lock以及区别

    1.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取锁之后因为异常,致锁 ...

  10. 在平衡树的海洋中畅游(三)——Splay

    Preface 由于我怕学习了Splay之后不直接写blog第二天就忘了,所以强行加了一波优先级. 论谁是天下最秀平衡树,我Splay第一个不服.维护平衡只靠旋转. 一言不合转死你 由于平衡树我也介绍 ...