用于在List中查找最小k个元素的更有效的解决方案

时间:2014-05-16 17:11:16

标签: scala big-o nearest-neighbor apache-spark

在下面的示例中,我试图返回“a”所属的最小2个元素(最近邻居)。

“a”中最小的两个元素基于:

List((("a","b"),1.0) , (("a","c"),4.0) , (("a","c"),3.0) , (("b","c"),2.0) )

 List((("a","b"),1.0) , (("a","c"),3.0)) 

这是我的解决方案:

    val l = List((("a","b"),1.0) , (("a","c"),4.0) , (("a","c"),3.0) , (("b","c"),2.0) )
                                                  //> l  : List[((String, String), Double)] = List(((a,b),1.0), ((a,c),4.0), ((a,c
                                                  //| ),3.0), ((b,c),2.0))
 val justA = l.filter(v => v._1._1.equals("a") || v._1._2.equals("a")).sortBy(_._2).take(2)
                                                  //> justA  : List[((String, String), Double)] = List(((a,b),1.0), ((a,c),3.0))

这个计算有更有效的解决方案吗?

1 个答案:

答案 0 :(得分:1)

在过滤步骤之后,您可以应用找到k个最小剩余元素的算法。这类似于这个问题:Algorithm to find k smallest numbers in array of n items

并概括一下我刚刚发布到那个问题的答案(因为在查找算法时我忘记了谁曾问过哪个问题):

有可能在O(n)时间内找到k个最小的n个元素(我的意思是真正的O(n)时间,而不是O(n + k的某个函数))。请参阅此处 - http://en.wikipedia.org/wiki/Selection_algorithm - 特别是关于“无序部分排序”和“中间选择作为枢轴策略”的小节,以及此处 - http://en.wikipedia.org/wiki/Median_of_medians - 用于制作此O的基本部分( n)中。

附录:如果你真的只需要找到两个最小的元素,那么,不是这个答案前面部分所描述的k元素,有两个很多可以在过滤步骤之后应用的更简单的O(n)算法。

算法1。在对剩余数据的一次传递中,找到最小的元素。将其取下并放在一边。然后找到剩下的最小元素。你现在有两个最小的元素;找到第一个的时间是O(n),找到第二个的时间是O(n),并且这一起仍然是O(n)。

算法2. 使用单淘汰锦标赛,找到剩余的最小元素。这需要n-1次比较。第二个最小的元素将是与最小元素进行比较的大约lg(n)元素之一(使用基数为2的对数),因此接下来在O(log n)时间内找到这些元素中最小的元素。所以这也是O(n),但比算法1的比较少。但是,在你的情况下,比较非常快,所以我可能只使用算法1.