允许插值的稀疏有序二维浮点数组的最佳数据结构(perl)
数据是股票期权。我想根据到期日(int)和货币的标准化距离(float)创建一个2D数组,值是标准化出价和要价的列表。如果所需的元素不在数组中,我希望能够在最近的元素之间进行插值 我看到3种可能的数据结构:允许插值的稀疏有序二维浮点数组的最佳数据结构(perl),perl,data-structures,Perl,Data Structures,数据是股票期权。我想根据到期日(int)和货币的标准化距离(float)创建一个2D数组,值是标准化出价和要价的列表。如果所需的元素不在数组中,我希望能够在最近的元素之间进行插值 我看到3种可能的数据结构: 一个稀疏的2D数组,可能有10000个元素,可能有1/3的空间 二维链表,即:每个数据元素有4个列表指针(因此3000个元素变为15000个) 一个2D散列(可能有3000个元素),每个维度中有2个键的排序列表(每个键可能有100个元素) 主要问题是需要插值时的有效检索。 使用任何方法检索现
有没有人对最有效的数据结构有什么建议。由于主要是按寿命进行查找,按距离进行查找,很少插入,因此我会使用排序数组通过二进制搜索查找记录
- 查找现有元素:O(日志N)
- 查找缺少元素的框:O(日志N)
- 插入:O(N)
my @data = (
[ $lifespan0, $distance0, $bid0, $ask0 ],
[ $lifespan1, $distance1, $bid1, $ask1 ],
...
);
my $lifespan_search_cmp = sub { $a <=> $data[$b][0] };
my $distance_search_cmp = sub { $a <=> $data[$b][1] };
插入:
my $i = binsearch_first \&$lifespan_search_cmp, $lifespan, @by_lifespan;
my $j = binsearch_first \&$distance_search_cmp, $distance, @by_distance;
push @data, [ $lifespan, $distance , $bid, $ask ];
splice(@by_lifespan, $i >= 0 ? $i : ~$i, 0, $#data);
splice(@by_distance, $j >= 0 ? $j : ~$j, 0, $#data);
潜艇:
sub-bin首先搜索(&$\@){
我的$compare=$\u0];
#我的$value=$\u1];
my$array=$\u2];
我的$min=0;
我的$max=$#$数组;
如果$max==-1,则返回-1;
my$ap=do{no strict'refs';\*{caller().::a'}};local*$ap;
my$bp=do{no strict'refs';\*{caller().::b'}};local*$bp;
*$ap=\($\[1]);
而($min[$mid]);
my$cmp=$compare->();
如果($cmp<0){
$max=$mid-1;
}
elsif($cmp>0){
$min=$mid+1;
}
否则{
如果$mid==$min,则返回$mid;
$max=$mid;
}
}
#将无符号整数转换为有符号整数。
退回拆包('j',包装('j',~$min));
}
子对象向前运行(&$\@){
我的$compare=$\u0];
#我的$value=$\u1];
我的$start=$\u2];
my$array=$\u3];
如果$start<0,则返回;
my$ap=do{no strict'refs';\*{caller().::a'}};local*$ap;
my$bp=do{no strict'refs';\*{caller().::b'}};local*$bp;
*$ap=\($\[1]);
我的$i=$start;
而($i[$i]);
my$cmp=$compare->()
最后,;
++$i;
}
返回wantarray?($start..$i-1):$i-1;
}
您可能希望在浮点比较(即在
$distance\u search\u cmp
中)中使用容差。由于您主要按寿命执行查找,按距离执行查找,并且插入很少,因此我会使用排序数组按二进制搜索查找记录
- 查找现有元素:O(日志N)
- 查找缺少元素的框:O(日志N)
- 插入:O(N)
my @data = (
[ $lifespan0, $distance0, $bid0, $ask0 ],
[ $lifespan1, $distance1, $bid1, $ask1 ],
...
);
my $lifespan_search_cmp = sub { $a <=> $data[$b][0] };
my $distance_search_cmp = sub { $a <=> $data[$b][1] };
插入:
my $i = binsearch_first \&$lifespan_search_cmp, $lifespan, @by_lifespan;
my $j = binsearch_first \&$distance_search_cmp, $distance, @by_distance;
push @data, [ $lifespan, $distance , $bid, $ask ];
splice(@by_lifespan, $i >= 0 ? $i : ~$i, 0, $#data);
splice(@by_distance, $j >= 0 ? $j : ~$j, 0, $#data);
潜艇:
sub-bin首先搜索(&$\@){
我的$compare=$\u0];
#我的$value=$\u1];
my$array=$\u2];
我的$min=0;
我的$max=$#$数组;
如果$max==-1,则返回-1;
my$ap=do{no strict'refs';\*{caller().::a'}};local*$ap;
my$bp=do{no strict'refs';\*{caller().::b'}};local*$bp;
*$ap=\($\[1]);
而($min[$mid]);
my$cmp=$compare->();
如果($cmp<0){
$max=$mid-1;
}
elsif($cmp>0){
$min=$mid+1;
}
否则{
如果$mid==$min,则返回$mid;
$max=$mid;
}
}
#将无符号整数转换为有符号整数。
退回拆包('j',包装('j',~$min));
}
子对象向前运行(&$\@){
我的$compare=$\u0];
#我的$value=$\u1];
我的$start=$\u2];
my$array=$\u3];
如果$start<0,则返回;
my$ap=do{no strict'refs';\*{caller().::a'}};local*$ap;
my$bp=do{no strict'refs';\*{caller().::b'}};local*$bp;
*$ap=\($\[1]);
我的$i=$start;
而($i[$i]);
my$cmp=$compare->()
最后,;
++$i;
}
返回wantarray?($start..$i-1):$i-1;
}
您可能希望在浮点比较(即在
$distance\u search\u cmp
中)中使用公差。是否需要插入到列表中,是插入的结果还是其他元素?如果不是,排序数组+binsearch听起来不错。编写一个binsearch很容易,这样它就可以返回一个索引,如果找不到该元素,它将在该索引中找到该元素(如图所示)。这要求最多进行日志(N)比较(3000个元素约12次),而不是使用现有的方法进行N次比较(3000个元素)。在C中插入需要Mn小于n/2指针,所以仍然很快。还考虑使用数据库(例如SQLite)。它应该让你以最小的努力接近最大的效率。谢谢ikegami-我不知道如何对2D数组进行排序。至于我现在使用的键列表数组,它们足够短(即“我不确定如何对2D数组进行排序”。根据您的搜索。如果您可以在两点之间插入结果,则必须对点进行排序,对吗?查找依据是什么?///如果您遵循我发布的链接,它还显示了如何插入排序数组。它是O(N),因此它的伸缩性比append+re-sort(O(N log N))稍好一些,而且速度也快得多。///firstidx必须进行线性搜索
sub binsearch_first(&$\@) {
my $compare = $_[0];
#my $value = $_[1];
my $array = $_[2];
my $min = 0;
my $max = $#$array;
return -1 if $max == -1;
my $ap = do { no strict 'refs'; \*{caller().'::a'} }; local *$ap;
my $bp = do { no strict 'refs'; \*{caller().'::b'} }; local *$bp;
*$ap = \($_[1]);
while ($min <= $max) {
my $mid = int(($min+$max)/2);
*$bp = \($array->[$mid]);
my $cmp = $compare->();
if ($cmp < 0) {
$max = $mid - 1;
}
elsif ($cmp > 0) {
$min = $mid + 1;
}
else {
return $mid if $mid == $min;
$max = $mid;
}
}
# Converts unsigned int to signed int.
return unpack('j', pack('J', ~$min));
}
sub get_run_forward(&$\@) {
my $compare = $_[0];
#my $value = $_[1];
my $start = $_[2];
my $array = $_[3];
return if $start < 0;
my $ap = do { no strict 'refs'; \*{caller().'::a'} }; local *$ap;
my $bp = do { no strict 'refs'; \*{caller().'::b'} }; local *$bp;
*$ap = \($_[1]);
my $i = $start;
while ($i <= $#$array) {
*$bp = \($array->[$i]);
my $cmp = $compare->()
and last;
++$i;
}
return wantarray ? ($start..$i-1) : $i-1;
}