Javascript 循环二元索引
我正在构建一个工具,通过最近的时间戳连接多个流。流可能不同步,因此我将最后的Javascript 循环二元索引,javascript,node.js,Javascript,Node.js,我正在构建一个工具,通过最近的时间戳连接多个流。流可能不同步,因此我将最后的n(可能>=500)项存储在固定大小的循环缓冲区中。我想使用sortedIndex(非搜索)查找缓冲区中的项目位置。我需要这个索引来查找时间戳前后的流项目 处理即将发生的问题的边缘情况并不重要,我不在乎是否返回数组外的索引或0的最大值。昨晚我在玩弄如何实现它,却找不出一个可行的实现 功能合同如下,基于() 一些测试用例(同样可以随意以不同的方式处理拐弯处的用例): function identity(x) { r
n
(可能>=500)项存储在固定大小的循环缓冲区中。我想使用sortedIndex
(非搜索
)查找缓冲区中的项目位置。我需要这个索引来查找时间戳前后的流项目
处理即将发生的问题的边缘情况并不重要,我不在乎是否返回数组外的索引或0
的最大值。昨晚我在玩弄如何实现它,却找不出一个可行的实现
功能合同如下,基于()
一些测试用例(同样可以随意以不同的方式处理拐弯处的用例):
function identity(x) {
return x;
}
function property(prop) {
return function(x) {
return x[prop];
};
}
test('sortedIndex should work on simple case', function(t) {
var array = [1, 2, 3, 4];
equal(sortedIndex(array, 2, identity), 1, 'equal case sorts towards left');
equal(sortedIndex(array, 2.5, identity), 2);
equal(sortedIndex(array, 10, identity), 0);
equal(sortedIndex(array, -10, identity), 3);
array = [{a: 1}, {a: 2}, {a: 3}, {a: 4}];
equal(sortedIndex(array, {a: 2}, property('a')), 1);
equal(sortedIndex(array, {a: 2.5}, property('a')), 2);
equal(sortedIndex(array, {a: 10}, property('a')), 0);
equal(sortedIndex(array, {a: -10}, property('a')), 3);
});
test('sortedIndex should work on circular collections', function() {
var array = [2, 3, 4, 1, 1.5];
equal(sortedIndex(array, 2, identity), 0, 'equal case sorts towards left');
equal(sortedIndex(array, 2.5, identity), 1);
equal(sortedIndex(array, 10, identity), 3);
equal(sortedIndex(array, -10, identity), 2);
equal(sortedIndex(array, 5, identity), 4);
equal(sortedIndex(array, 3.5, identity), 3);
array = [{a: 2}, {a: 3}, {a: 4}, {a: 1}, {a: 1.5}];
equal(sortedIndex(array, {a: 2}, property('a')), 0, 'equal case sorts towards left');
equal(sortedIndex(array, {a: 2.5}, property('a')), 1);
equal(sortedIndex(array, {a: 10}, property('a')), 3);
equal(sortedIndex(array, {a: -10}, property('a')), 2);
});
编辑---这是我完成的版本
sortedIndex:函数(值、比较器、上下文){
var low=此.start,
高=此尺寸-1;
//棘手的部分是找出它是在枢轴之前还是之后
//我们可以通过检查目标是否小于
//最后一项。之后就是典型的二进制搜索。
if(low&&comparitor.call(上下文、值、this.data[high])>0){
低=0,高=this.end;
}
while(低<高){
var mid=(低+高)>>>1;
如果(comparitor.call(context,value,this.data[mid])>0)low=mid+1;
否则高=中;
}
// http://stackoverflow.com/a/18618273/1517919
返回(((低-this.start)%this.size)+this.size)%this.size;
}
通常情况下,您会存储实际占用位置的开始和结束。有了这些信息,这应该是相当微不足道的,因为我们可以区分三种情况:
function sortedIndex(buffer, item, getValue) {
if (buffer.start < buffer.end)
// do standard binary search between start and end indices
else if (getValue(buffer[0]) <= getValue(item))
// do standard binary search between 0 and end index
else // getValue(buffer[0] > getValue(item)
// do standard binary search between start and buffer.length
}
函数sortedIndex(缓冲区、项、getValue){
if(buffer.start
这是我的想法(它通过了测试用例)。基本上,当数组排序时,它会执行普通的二进制搜索。当它是圆形的(例如:[2,3,4,1])时,它会找到轴(这是圆开始的索引,因此在该示例中,与数组中的4对应的索引3将是轴),然后二进制搜索枢轴所在的数组部分
function findPivot(arr, low, high, iterable){
// base cases
if (high < low) return -1;
if (high == low) return low;
var mid = Math.floor((low + high)/2);
if (mid < high && iterable(arr[mid]) > iterable(arr[mid + 1]))
return mid;
if (mid > low && iterable(arr[mid]) < iterable(arr[mid - 1]))
return (mid-1);
if (iterable(arr[low]) >= iterable(arr[mid]))
return findPivot(arr, low, mid-1, iterable);
else
return findPivot(arr, mid + 1, high, iterable);
}
function binarySearch(arr, low, high, val, iterable)
{
if (high < low)
return low;
var mid = Math.floor((low + high)/2);
if (iterable(val) == iterable(arr[mid]))
return mid;
if (iterable(val) > iterable(arr[mid]))
return binarySearch(arr, (mid + 1), high, val, iterable);
else
return binarySearch(arr, low, (mid -1), val, iterable);
}
function sortedIndex(array, value, iterable) {
var arr_size = array.length;
var pivot = findPivot(array, 0, arr_size-1, iterable);
if (pivot == -1) {
if(iterable(array[arr_size-1]) < iterable(value)){
return 0;
} else if(iterable(array[0]) > iterable(value)){
return arr_size-1;
}
return binarySearch(array, 0, arr_size-1, value, iterable);
}
if(iterable(array[pivot]) < iterable(value)){
return pivot+1;
} else if(iterable(array[pivot+1]) > iterable(value)){
return pivot;
}
if (iterable(array[pivot]) == iterable(value))
return pivot;
if (iterable(array[0]) <= iterable(value))
return binarySearch(array, 0, pivot-1, value, iterable);
else
return binarySearch(array, pivot+1, arr_size-1, value, iterable);
}
函数findPivot(arr、低、高、可调){
//基本情况
如果(高<低)返回-1;
如果(高==低)返回低;
var mid=数学楼层((低+高)/2);
if(中<高和可调(arr[mid])>可调(arr[mid+1]))
中途返回;
if(中>低和可调(arr[mid])=可调(arr[mid]))
返回findPivot(arr、低、中1、iterable);
其他的
返回findPivot(arr,中+1,高,可调);
}
函数二进制搜索(arr、low、high、val、iterable)
{
如果(高<低)
低回报;
var mid=数学楼层((低+高)/2);
if(iterable(val)=iterable(arr[mid]))
中途返回;
if(可调(val)>可调(arr[mid]))
返回二进制搜索(arr,(mid+1),high,val,iterable);
其他的
返回二进制搜索(arr,low,(mid-1),val,iterable);
}
函数sortedIndex(数组、值、iterable){
var arr_size=array.length;
var pivot=findPivot(数组,0,arr_size-1,iterable);
如果(枢轴==-1){
if(iterable(数组[arr_size-1])iterable(值)){
返回arr_size-1;
}
返回二进制搜索(数组,0,arr_size-1,值,iterable);
}
if(iterable(数组[pivot])iterable(值)){
返回轴;
}
if(iterable(数组[pivot])==iterable(值))
返回轴;
if(iterable(数组[0])快速评论,我认为您在测试用例中犯了一个错误;属性函数,x
未定义,因为内部函数的参数名称不正确prop
。在functionsortedIndex
中,您将参数取为iterable
,并将其作为迭代器调用。感谢您在一辆火车上写的没有测试的ide:)什么是圆形数组的“枢轴”?枢轴是它开始的索引(有点像在快速排序中),例如在[3,4,5,1,2,3]中,枢轴将是2(对应于5),我明白你的意思,但是5是它结束的地方(1是它开始的地方),如果你能想出一个迭代的binarySearch
(像下划线一样)我会奖励你。另外,Math.floor(x/2)
可以编写x>>1
:)更新以添加迭代二进制搜索和findPivot
function sortedIndex(buffer, item, getValue) {
if (buffer.start < buffer.end)
// do standard binary search between start and end indices
else if (getValue(buffer[0]) <= getValue(item))
// do standard binary search between 0 and end index
else // getValue(buffer[0] > getValue(item)
// do standard binary search between start and buffer.length
}
function findPivot(arr, low, high, iterable){
// base cases
if (high < low) return -1;
if (high == low) return low;
var mid = Math.floor((low + high)/2);
if (mid < high && iterable(arr[mid]) > iterable(arr[mid + 1]))
return mid;
if (mid > low && iterable(arr[mid]) < iterable(arr[mid - 1]))
return (mid-1);
if (iterable(arr[low]) >= iterable(arr[mid]))
return findPivot(arr, low, mid-1, iterable);
else
return findPivot(arr, mid + 1, high, iterable);
}
function binarySearch(arr, low, high, val, iterable)
{
if (high < low)
return low;
var mid = Math.floor((low + high)/2);
if (iterable(val) == iterable(arr[mid]))
return mid;
if (iterable(val) > iterable(arr[mid]))
return binarySearch(arr, (mid + 1), high, val, iterable);
else
return binarySearch(arr, low, (mid -1), val, iterable);
}
function sortedIndex(array, value, iterable) {
var arr_size = array.length;
var pivot = findPivot(array, 0, arr_size-1, iterable);
if (pivot == -1) {
if(iterable(array[arr_size-1]) < iterable(value)){
return 0;
} else if(iterable(array[0]) > iterable(value)){
return arr_size-1;
}
return binarySearch(array, 0, arr_size-1, value, iterable);
}
if(iterable(array[pivot]) < iterable(value)){
return pivot+1;
} else if(iterable(array[pivot+1]) > iterable(value)){
return pivot;
}
if (iterable(array[pivot]) == iterable(value))
return pivot;
if (iterable(array[0]) <= iterable(value))
return binarySearch(array, 0, pivot-1, value, iterable);
else
return binarySearch(array, pivot+1, arr_size-1, value, iterable);
}
function findPivot(arr, low, high, iterable)
{
while(true){
// base cases
if (high < low) return -1;
if (high == low) return low;
var mid = (low + high) >>> 1;
if (mid < high && iterable(arr[mid]) > iterable(arr[mid + 1]))
return mid;
if (mid > low && iterable(arr[mid]) < iterable(arr[mid - 1]))
return (mid-1);
if (iterable(arr[low]) >= iterable(arr[mid]))
high = mid-1;
else
low = mid + 1;
}
}
function binarySearch(arr, low, high, val, iterable)
{
while(true){
if (high < low)
return low;
var mid = (low + high) >>> 1;
if (iterable(val) == iterable(arr[mid]))
return mid;
if (iterable(val) > iterable(arr[mid]))
low = mid + 1;
else
high = mid -1;
}
}
function sortedIndex(array, value, iterable) {
var arr_size = array.length;
var pivot = findPivot(array, 0, arr_size-1, iterable);
if (pivot == -1) {
if(iterable(array[arr_size-1]) < iterable(value)){
return 0;
} else if(iterable(array[0]) > iterable(value)){
return arr_size-1;
}
return binarySearch(array, 0, arr_size-1, value, iterable);
}
if(iterable(array[pivot]) < iterable(value)){
return pivot+1;
} else if(iterable(array[pivot+1]) > iterable(value)){
return pivot;
}
if (iterable(array[pivot]) == iterable(value))
return pivot;
if (iterable(array[0]) <= iterable(value))
return binarySearch(array, 0, pivot-1, value, iterable);
else
return binarySearch(array, pivot+1, arr_size-1, value, iterable);
}