获得序列中n个最小的数字

时间:2011-10-02 05:24:51

标签: algorithm clojure

从序列中获取n个最小数字的最有效方法是什么

[ [1 2 3] [9 2 1] [2 3 4] [5 6 7] ]

我想根据第一项

从序列中取2个最小值
[1 2 3] [2 3 4]

目前我正在对整个列表进行排序,然后采取前n项,但这可能不是最有效的方法,这是一个很大的列表,我需要经常这样做。

3 个答案:

答案 0 :(得分:3)

如上所述,您可以使用中位数中值算法在线性时间中选择第k个最小元素,然后在线性时间内进行分区。这将为您提供O(n)中的k个最小元素。然而,元素将是未排序的,因此如果您希望排序的k个最小元素将花费您另一个O(klogk)。

一些重要的注意事项:

  1. 首先,虽然复杂度为O(n),但小的常数并不能得到保证,并且您可能会发现最小的改进,特别是如果您的n相当小。有一些随机线性选择算法可以在更好的实际时间内运行(通常预期的运行时间是O(n),最坏的情况更糟,但它们的常数比确定的更小)。

  2. 为什么你不能以排序的方式维护数组?这可能会更高效。您只需要将每个元素插入到正确的位置,这需要花费O(logn),但是找到k最小值则为O(1)(如果必须重新构建数组,则为O(k))。

  3. 如果你决定反对上面的注释,那么另一种方法是在每个这样的过程之后保持数组排序,在数组的末尾提供插入O(1),然后每次执行“合并排序”你需要找到k个最小元素的时间。即您只需 新的,然后在线性时间内合并它们。因此,这将花费O(mlogm + n),其中m是自上次排序以来添加的元素数量。

答案 1 :(得分:3)

Joy of Clojure,第6.4章描述了一种惰性排序算法。懒惰排序的优点在于它只需要做很多工作就可以找到前面的x值。所以如果x<<这个算法是O(n)。这是该算法的修改版本。

(defn sort-parts                                                                                                                                                                                                            
  [work f]                                                                                                                                                                                                                  
  (lazy-seq                                                                                                                                                                                                                 
   (loop [[part & parts] work]                                                                                                                                                                                              
     (if-let [[pivot & xs] (seq part)]                                                                                                                                                                                      
       (let [psmaller? (partial f pivot)]                                                                                                                                                                                   
         (recur (list* (filter psmaller? xs)                                                                                                                                                                                
                       pivot                                                                                                                                                                                                
                       (remove psmaller? xs)                                                                                                                                                                                
                       parts)))                                                                                                                                                                                             
       (when-let [[x & parts] parts]                                                                                                                                                                                        
         (cons x                                                                                                                                                                                                            
               (sort-parts parts f)))))))                                                                                                                                                                                   

(defn qsort [xs f] (sort-parts (list xs) f))                                                                                                                                                                                

(defn cmp [[a _ _] [b _ _]] (> a b))                                                                                                                                                                                        

(def a [[1 2 3] [9 2 1]  [2 3 4] [5 6 7]])                                                                                                                                                                                   

(take 2 (qsort a cmp)) 

答案 2 :(得分:0)

如果n很小,您可以创建第二个大小为n的列表,并保持排序,这样您就可以快速访问该列表中的最大值; 遍历大列表,检查每个小于列表中的最大值; 如果是这样,将其插入小清单......小清单已满,弹出之前的最旧清单。

如果n小于3或4,你可以强制它。如果n可以更大,您将需要进行二分搜索以找到每个的插入点。如果n可能非常大,那么可能会有不同的机制。