Sorting 具有极快插入时间的结构

Sorting 具有极快插入时间的结构,sorting,data-structures,insertion-sort,Sorting,Data Structures,Insertion Sort,我正在寻找一个有序的数据结构,允许非常快的插入。这是唯一需要的财产。只能从顶部元素访问和删除数据 更精确地说,我需要两个结构: 1) 第一个结构应该允许使用int值进行有序插入。完成插入后,应报告插入元素的排名 2) 第二个结构应允许在指定的列组中插入 要存储的元素数可能是数千或数万 [编辑]我必须修正体积假设:尽管在任何时候,有序结构的大小可能在数万范围内,但每次运行的插入总数可能在数千万范围内 在O(1)中插入时间会很好,尽管O(log(log(n))也是可以接受的。目前,我只为第一个结构找

我正在寻找一个有序的数据结构,允许非常快的插入。这是唯一需要的财产。只能从顶部元素访问和删除数据

更精确地说,我需要两个结构:

1) 第一个结构应该允许使用int值进行有序插入。完成插入后,应报告插入元素的排名

2) 第二个结构应允许在指定的列组中插入

要存储的元素数可能是数千或数万

[编辑]我必须修正体积假设:尽管在任何时候,有序结构的大小可能在数万范围内,但每次运行的插入总数可能在数千万范围内


在O(1)中插入时间会很好,尽管O(log(log(n))也是可以接受的。目前,我只为第一个结构找到了一些有趣的候选者,但要么在log(n)中,要么没有报告插入排名的功能(这是必需的)。

顺序统计树在O(LogN)时似乎适合您的需要

订单统计信息树是一个扩展(请参见增强数据结构)版本的
BinarySearchTree,支持额外的操作秩(x),它返回秩 x(即键小于或等于x的元素数)和FindByRank(k), 返回树的第k个最小元素

如果您只有数万个元素,那么O(LogN)时间和O(1)时间渐近时间复杂度之间的性能差异就没有您想象的那么显著。例如,考虑100000个元素,Logn方法只慢16倍。

对数(100000)/对数(2)=16.6096405

在这种情况下,系数差异(实现、开销)可能是优化的真正目标。由于继承的复杂性,奇特的数据结构通常具有更高的开销(有时慢数千倍)。它们更可能来自不太完善的实现,因为它们使用较少


您应该对不同的堆实现进行基准测试(实际测试),以找到具有最佳实际性能的实现

你说你需要一个有序的数据结构,对我来说,这听起来像是你需要一个能够产生O(n)时间中包含的所有元素的东西

但是你说你将只访问顶部(最少?)元素,这意味着你真的只需要一些可以产生最小值的东西,重复地——打开一扇通向偏序的门


是哪一个?

如果我正确理解了你的问题,我建议你使用一本字典,它的键是等级,值是链表

使用关键点可以具有列组,使用链表作为值,可以具有O(1)个插入时间。同样作为删除,您可以有O(1)。您可以使用linkedlist实现堆栈或队列,这正是您所需要的

或者,您可以使用一个双链接列表,其中保证有O(1)个插入和删除。对于排名,您可以将该信息嵌入到节点中。

关于一种形式的,特别是链接文章中的“索引skiplist”如何。这将为您的两个用例提供O(lgn)插入和查找,以及O(1)访问第一个节点的权限

--编辑--


当我想到O(1)算法时,我想到的是基于基数的方法。这是一个返回秩的O(1)插入。这样做的目的是将密钥分解为多个半字节,并对所有插入的具有该前缀的项进行计数。不幸的是,这个常数很高(我一直在研究堆数据结构;但是,尽管它们提供了一些非常好的插入速度和快速的顶级元素检索,但它们似乎没有提供插入元素的排名,也不允许在指定的排名插入。您查看过顺序统计树吗?。这似乎是为您的需要而设计的。我有一笔费用我认为,如果您需要了解数据结构的“中间”部分,那么您不会比日志(n)时间和树做得更好。我不建议使用堆,因为每次插入节点时您都必须进行堆化,最终会得到O(nlogn)@desmond:这很有趣,我会研究一下。谢谢当你说有序时,你是说保持插入的顺序?还是排序?你能解释一下为什么数组(可能是预先分配的,或者根据需要动态调整大小为更大的)吗不符合您的条件?或链表?我怀疑您还有其他未列出的要求。@DarthVader:是,“已排序”。每次插入后都应对结构进行排序。@Phrogz:事实上,我目前的幼稚实现确实使用链表和环表。它们可以工作。但它们不尊重O(1)(或足够接近)属性。它们太慢了。想想当尝试将一个元素插入10K排序列表/表的中间时会发生什么…@Cyan啊,插入到中间。当您说“有序数据结构”但没有指定顺序时,我想您可能是指“尊重插入顺序”。您的意思是您想要一个执行排序插入的数据结构(我假设是针对某些排序标准)。好的观点。真正的问题是,我需要在插入元素时检索排名。因此,我猜必须对结构进行排序/排序才能提供排名。事实上,我正在考虑这种可能性。可以是一个很好的候选者。它看起来尽可能好。我也在考虑类似的想法,使用Fenwick树。我担心大内存需求会降低性能,因为这也意味着频繁的非缓存内存访问。但至少值得一试。这看起来是一个有趣的命题,但我还不太明白。键怎么会变为秩?秩应该在每次插入后一直变化
int *p1;int *p2;int *p3;int *p4;
void **records;
unsigned int min = 0xFFFF;

int init(void)     {
   p1 = (int*)calloc(16,sizeof(int));
   p2 = (int*)calloc(256, sizeof(int));
   p3 = (int*)calloc(4096, sizeof(int));
   p4 = (int*)calloc(65536,sizeof(int));
   records = (void**)calloc(65536,sizeof(void*));
   return 0;
}

//records that we are storing one more item, 
//counts the number of smaller existing items
int Add1ReturnRank(int* p, int offset, int a) {
   int i, sum=0;
   p+=offset;
   for (i=0;i<a;i++)
      sum += p[i];
   p[i]++;
   return sum;
}

int insert(int key, void* data) {
   unsigned int i4 = (unsigned int)key;
   unsigned int i3= (i4>> 4);
   unsigned int i2= (i3>> 4);
   unsigned int i1= (i2>> 4);
   int rank = Add1ReturnRank(p1,0, i1&0xF);
   rank += Add1ReturnRank(p2,i2&0xF0,i2&0xF);
   rank += Add1ReturnRank(p3,i3&0xFF0,i3&0xF);
   rank += Add1ReturnRank(p4,i4&0xFFF0,i4&0xF);
   if (min>key) {min = key;}
   store(&records[i4],data);
   return rank;
}
void* getMin(int* key) {
    return data[*key=min];
}

void* removeMin(int* key)  {
   int next = 0;
   void* data = records[min];
   unsigned int i4 = min;
   unsigned int i3= (i4>> 4);
   unsigned int i2= (i3>> 4);
   unsigned int i1= (i2>> 4);

   p4[i4]--;
   p3[i3]--;
   p2[i2]--;
   p1[i1]--;
   *key = min;
   while (!p1[i1]) {
      if (i1==15) { min = 0xFFFF; return NULL;}
      i2 = (++i1)<<4;
   }
   while (!p2[i2])
      i3 = (++i2)<<4;
   while (!p3[i3])
      i4 = (++i3)<<4;
   while (!p4[i4])
      ++i4;
   min = i4;
   return data;
}