Top N record sort仅返回排序数组中特定范围内的数字

Top N record sort仅返回排序数组中特定范围内的数字,c,arrays,algorithm,sorting,C,Arrays,Algorithm,Sorting,我有一个哈希表,它可能包含大约1-5百万条记录。我需要遍历它来选择其中的一些条目,然后按照某种顺序对它们进行排序。另外,我实际上并不需要所有排序的元素,而是说一些属于特定范围的元素。例如,如果哈希表包含一百万条记录,我可能只需要前1000-2000条记录。有标准的排序算法吗?如果不是,我可以实现一个2次通过算法,第一次通过找到第1000条记录,然后说下一次通过确定下一个1000条记录可能是什么。是否有任何堆排序的实现可用于此?我想任何topN堆排序的实现也会对这一点有所帮助。我可以使用的数组大小

我有一个哈希表,它可能包含大约1-5百万条记录。我需要遍历它来选择其中的一些条目,然后按照某种顺序对它们进行排序。另外,我实际上并不需要所有排序的元素,而是说一些属于特定范围的元素。例如,如果哈希表包含一百万条记录,我可能只需要前1000-2000条记录。有标准的排序算法吗?如果不是,我可以实现一个2次通过算法,第一次通过找到第1000条记录,然后说下一次通过确定下一个1000条记录可能是什么。是否有任何堆排序的实现可用于此?我想任何topN堆排序的实现也会对这一点有所帮助。我可以使用的数组大小也有一个限制。如果数组大小仅为请求的记录数,那将是最好的

您可以使用
快速排序中使用的分区算法。该算法称为“quickselect”,用于
c++
实现
n\u元素
。使用这种方法,您将能够在线性时间内解决您的问题。有关更多信息,请参阅维基百科的文章


此算法使您能够在线性时间内修改输入数组,以便位置
n
之后的所有元素都大于位置n处的元素,而位置
n
之前的所有元素都小于位置
n
处的元素。现在,假设您想知道哪些元素位于数组
A
B
的位置。然后首先对位置
B
应用一次算法。因此,我们感兴趣的所有元素都在区间
[0,B]
中。现在,这一次只对结束于位置B的子阵列再次应用算法,参数为
A
。现在您将拥有区间
[A,B]
中的所有元素。注意元素的顺序是任意的。

您可以使用
快速排序中使用的分区算法。该算法称为“quickselect”,用于
c++
实现
n\u元素
。使用这种方法,您将能够在线性时间内解决您的问题。有关更多信息,请参阅维基百科的文章


此算法使您能够在线性时间内修改输入数组,以便位置
n
之后的所有元素都大于位置n处的元素,而位置
n
之前的所有元素都小于位置
n
处的元素。现在,假设您想知道哪些元素位于数组
A
B
的位置。然后首先对位置
B
应用一次算法。因此,我们感兴趣的所有元素都在区间
[0,B]
中。现在,这一次只对结束于位置B的子阵列再次应用算法,参数为
A
。现在您将拥有区间
[A,B]
中的所有元素。注意,元素的顺序是任意的。

有一个标准的算法。正如@Ivaylo Strandjev在他的回答中指出的那样,quickselect是实现这一点的典型方式。然而,在这种情况下,这将需要O(n)个额外的空间,因为您无法重新排列哈希表

另一种常用的方法是堆。如果你想要第1000到2000个最小的项目,你可以分两次完成。首先,使用堆查找第1000个最小的项。然后,您再进行一次传递,以获得1000个最小的项目,这些项目大于或等于您在第一次传递中找到的项目。比如:

第一关:

h = new max heap
add first 1000 items to heap
for i = 1000 to n-1
    if hashtable[i] < heap.peek()
        heap.remove_first()
        heap.add(item)
现在创建一个大小为1000的新堆并添加该项。然后再次浏览列表,只添加>=最小的项目:

h = new max heap
for i = 0 to n-1
    if hashtable[i] >= smallest
        if heap.count < 1000
            heap.add(item)
        else if hashtable[i] < heap.peek()
            heap.remove_first()
            heap.add(item)
h=新的最大堆
对于i=0到n-1
如果哈希表[i]>=最小
如果heap.count<1000
添加(项)
如果哈希表[i]
完成后,堆包含1000到2000项

这种技术的一个优点是,您可以分配单个数组,并像堆一样对其进行操作。有关概述,请参阅,或查看我的。前三篇文章解释了这个问题,并提供了足够的信息,使您能够用C实现一个简单的堆

不过,请记住,我在上面的示例中使用的是Max堆。我博客中的讨论是关于Min heap的,因此您必须确保相应地更改比较

堆选择的复杂性是O(n logk),其中n是列表的大小,k是要选择的项目数。如果希望在数组中返回项目时对其进行排序,则必须对堆进行排序(或逐个删除项目)。无论哪种情况,这都是O(k log k)。因此,您的总运行时间将与
(n log k)+(k log k)
成比例

尽管quickselect比heap select渐进地快,但实际上,当您选择1%或更少的项时,heap select通常比quickselect快。因此,如果从一百万个项目列表中选择1000个项目,堆选择几乎肯定会更快。有关详细信息,请参阅

更新 正如OP在评论中指出的,这可能需要相当大的堆。例如,如果要查找第10000到11000个项目,第一次传递需要大小为10000的堆。第二次传递仍然只需要1000个项目的堆。使用naive方法,选择第990000到9990000项需要大小为998000的堆。但是,您可以改变这种情况:使用最小堆,然后您只需要再次使用大小为1000的堆(即,查找第1000到2000个最大的项目)。因此,第一次传递所需的堆大小是
min
h = new max heap
for i = 0 to n-1
    if hashtable[i] >= smallest
        if heap.count < 1000
            heap.add(item)
        else if hashtable[i] < heap.peek()
            heap.remove_first()
            heap.add(item)