查找未排序列表的第N项而不排序列表

时间:2009-06-23 20:04:41

标签: python arrays sorting

嘿。我有一个非常大的数组,我想找到第N个最大的值。平凡我可以对数组进行排序,然后取第N个元素,但我只对一个元素感兴趣,所以有可能比排序整个数组更好...

10 个答案:

答案 0 :(得分:20)

堆是这个操作的最佳数据结构,Python有一个很好的内置库来实现这一点,称为heapq。

import heapq

def nth_largest(n, iter):
    return heapq.nlargest(n, iter)[-1]

示例用法:

>>> import random
>>> iter = [random.randint(0,1000) for i in range(100)]
>>> n = 10
>>> nth_largest(n, iter)
920

通过排序确认结果:

>>> list(sorted(iter))[-10]
920

答案 1 :(得分:18)

排序至少需要O(nlogn)运行时 - 非常高效的selection algorithms可以在线性时间内解决您的问题。

Partition-based selection(有时是Quick select),基于quicksort(递归分区)的思想,是一个很好的解决方案(请参阅伪代码+ Another example的链接)。

答案 2 :(得分:3)

您可以迭代整个序列,维护您找到的5个最大值的列表(这将是O(n))。话虽如此,我认为对列表进行排序会更简单。

答案 3 :(得分:3)

一个简单的改进的快速排序在实践中非常有效。它的平均运行时间与N成正比(尽管最坏情况下,运气运行时间为O(N ^ 2))。

像快速排序一样继续。随机选择一个透视值,然后流过您的值并查看它们是否高于或低于该透视值,并根据该比较将它们放入两个箱中。 在快速排序中,您将以递归方式对这两个箱中的每一个进行排序。但是对于第N个最高值计算,您只需要对其中一个箱子进行排序。每个箱子的数量会告诉您哪个箱子保持您的第n个最高值。因此,例如,如果你想要第125个最高值,并且你分成两个箱子,其中75个在“高”箱中,150个在“低”箱中,你可以忽略高箱,然后继续找到125-75 =单独低位箱中的第50个最高值。

答案 4 :(得分:3)

你可以试试Median of Medians方法 - 它的速度是O(N)。

答案 5 :(得分:1)

使用heapsort。在您绘制元素之前,它只会对列表进行部分排序。

答案 6 :(得分:1)

你基本上想要产生一个“前N个”列表并选择该列表末尾的列表。

因此,当largeArray项目大于前N个列表的最后一项时,您可以扫描数组并插入空列表,然后删除最后一项。

完成扫描后,选择前N个列表中的最后一项。

整数和N = 5的例子:

int[] top5 = new int[5]();
top5[0] = top5[1] = top5[2] = top5[3] = top5[4] = 0x80000000; // or your min value

for(int i = 0; i < largeArray.length; i++) {
    if(largeArray[i] > top5[4]) {
       // insert into top5:
       top5[4] = largeArray[i];

       // resort:
       quickSort(top5);
    }
}

答案 7 :(得分:1)

正如人们所说,一旦跟踪K最大值,您就可以走在列表中。如果K很大,则该算法将接近O(n 2 )。

但是,您可以将第K个最大值存储为二叉树,操作变为O(n log k)。

根据维基百科,这是最好的选择算法:

 function findFirstK(list, left, right, k)
     if right > left
         select pivotIndex between left and right
         pivotNewIndex := partition(list, left, right, pivotIndex)
         if pivotNewIndex > k  // new condition
             findFirstK(list, left, pivotNewIndex-1, k)
         if pivotNewIndex < k
             findFirstK(list, pivotNewIndex+1, right, k)

其复杂性为O(n)

答案 8 :(得分:0)

如果在生产代码中,您应该做的一件事是使用您的数据样本进行测试。 例如,您可以考虑1000或10000个元素的“大”数组,并从配方中编写quickselect方法。

已排序的编译性质及其有些隐藏和不断发展的优化使得它比在中小型数据集(&lt; 1,000,000个元素)上的python编写的quickselect方法更快。此外,您可能会发现,当您将数组的大小增加到超过该数量时,可以在本机代码中更有效地处理内存,并且继续获益。

因此,即使quickselect是O(n)vs sorted的O(nlogn),也没有考虑处理每n个元素需要多少实际的机器代码指令,对流水线的任何影响,处理器缓存的使用和排序的创建者和维护者将烘焙到python代码中的其他东西。

答案 9 :(得分:0)

您可以为每个元素保留两个不同的计数——大于该元素的元素数和小于该元素的元素数。

然后做一个 if 检查 N == 大于每个元素的元素数 -- 满足上述条件的元素就是你的输出

检查以下解决方案

def NthHighest(l,n):
    if len(l) <n:
        return 0

    for i in range(len(l)):
        low_count = 0
        up_count = 0

        for j in range(len(l)):
            if l[j] > l[i]:
                up_count = up_count + 1
            else:
                low_count = low_count + 1

        # print(l[i],low_count, up_count)
        if up_count == n-1:
            #print(l[i])
            return l[i]

# # find the 4th largest number 

l = [1,3,4,9,5,15,5,13,19,27,22]
print(NthHighest(l,4))  

-- 使用上述解决方案,您可以找到两者 - Nth highest as well as Nth Lowest