Как насчет формы списка пропуска, в частности "индексированного списка пропуска" в связанной статье? . Это должно дать O (lg N) вставку и поиск, а также O (1) доступ к первому узлу для обоих ваших вариантов использования.
--Редактировать--
Когда я думаю об алгоритмах O(1), я думаю о методах счисления. Вот вставка O(1) с возвращенным рангом. Идея состоит в том, чтобы разбить ключ на фрагменты и вести подсчет всех вставленных элементов, имеющих этот префикс. К сожалению, константа велика (‹=64 разыменования и добавления), а объем памяти равен O(2 x 2^INT_BITS), что ужасно. Это версия для 16-битных целых чисел, расширение до 32 бит должно быть простым.
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;
}
Эта структура также поддерживает O(1) GetMin и RemoveMin. (GetMin работает мгновенно, Remove имеет константу, аналогичную Insert.)
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;
}
Если ваши данные разрежены и хорошо распределены, вы можете удалить счетчик p4
и вместо этого выполнить сортировку вставками на уровне P3. Это уменьшит затраты на хранение на 16 за счет более высокой вставки в наихудшем случае, когда имеется много похожих значений.
Другой идеей по улучшению хранилища может быть объединение этой идеи с чем-то вроде Extendable Hash. Используйте целочисленный ключ в качестве хеш-значения и ведите подсчет вставленных узлов в каталоге. Выполнение суммирования соответствующих записей словаря во вставке (как указано выше) по-прежнему должно быть O (1) с большой константой, но хранилище уменьшится до O (N)
person
AShelly
schedule
07.12.2011