Структура данных для хранения уникальных элементов
Я ищу структуру данных, которая должна предпочтительно выполнять равную O (1)? для любого количества элементов при добавлении/удалении / извлечении элементов.
вот некоторые дополнительные рекомендации,
- извлечение элементов не должно включать медленное
keys()
- элементы должны быть всегда уникальными и определенными
- порядок элементов не важен
- добавление или удаление элемента не должно включать итерацию над другими элементы
- пробелы в извлеченном списке элементов допустимы и могут быть представлены с помощью
undef
стоимостью
пожалуйста, предложите лучшее решение, чем,
sub uniqArrayFactory {
my $members = [];
my $seen = {};
my $gaps = [];
return sub {
my (%arg) = @_;
return $members if $arg{members};
my $m;
if (defined ($m = $arg{del})) {
return if !$seen->{$m};
${ $seen->{$m} } = undef;
push @$gaps, delete($seen->{$m});
}
elsif (defined ($m = $arg{add})) {
return if $seen->{$m};
if (@$gaps) {
$seen->{$m} = pop @$gaps;
${ $seen->{$m} } = $m;
}
else {
push @$members, $m;
$seen->{$m} = ( $members->[-1] );
}
}
return $m;
};
}
обновление (использования)
my $fa = uniqArrayFactory();
$fa->(add => 10);
$fa->(del => 10);
my $members = $fa->(mebers => 1);
2 ответов
keys
и each
действительно удивительно медленно. Но если вы храните каждый элемент как значение хэша и используете values
, все сделать быстрее. С
use strict;
use warnings;
use Benchmark qw(:all);
my $i;
my $fa;
my %hash;
my %compare = (
uarray => sub {
$fa->(add => $i++);
my $memb = $fa->(members => 1);
for my $v (@$memb) { next if !defined $v; }
},
hash => sub {
$hash{ $i } = $i;
for my $v (values %hash) {}
$i++;
},
);
$i = 0; $fa = uniqArrayFactory(); %hash = ();
cmpthese(10000, \%compare);
sub uniqArrayFactory {
my $members = [];
my $seen = {};
my $gaps = [];
return sub {
my (%arg) = @_;
return $members if exists $arg{members};
my $m;
if (defined ($m = $arg{del})) {
return if !$seen->{$m};
${ $seen->{$m} } = undef;
push @$gaps, delete($seen->{$m});
}
elsif (defined ($m = $arg{add})) {
return if $seen->{$m};
if (@$gaps) {
$seen->{$m} = pop @$gaps;
${ $seen->{$m} } = $m;
}
else {
push @$members, $m;
$seen->{$m} = \( $members->[-1] );
}
}
return $m;
};
}
Я:
Rate hash uarray
hash 3205/s -- -6%
uarray 3401/s 6% --
как ни странно, может быть Tie::IxHash
, который был мотивирован желанием получить ключи хэша в указанном порядке, настолько близок, насколько вы собираетесь получить то, что хотите.
на на Tie::IxHash
реализация, ключи и значения, хранящиеся в массиве ссылок. keys
возвращает копию набора ключей, но что-то вроде (tied %hash)->[1]
даст вам прямой доступ к нему.
удаление элементов в элементе Tie::IxHash
является O (n). Возможно обходным путем для этого было бы заменить значения на undef
вместо того, чтобы удалять их. То есть, предпочитая
$ixhash{$obsolete_key} = undef;
to
delete $ixhash{$obsolete_key};
или если бы вы могли объединить свои удаления - если бы вы могли организовать свой код так, чтобы вы обычно вызывали delete
на нескольких ключах примерно в то же время и между другими операциями над хэшем-тогда есть возможности для улучшения на Tie::IxHash
.