【问题标题】:Binary search - multiple searched values二进制搜索 - 多个搜索值
【发布时间】:2020-08-23 16:51:16
【问题描述】:

我使用二进制搜索来搜索应该在我的应用程序中呈现的行范围。 GridRow 有 3 个属性:topheightbottom,并且行列表已排序。

例子:

我将30px 传递给我的第一个电话rowBinarySearch,在下一行140firstIndex 以加速搜索。我返回 lastIndex + 1 以修复数组中最后一行的可见性:

const firstIndex = rowBinarySearch(rows, 30);
const lastIndex = rowBinarySearch(rows, 140, firstIndex);

return range.slice(firstIndex, lastIndex + 1);

搜索功能实现:

function rowBinarySearch(arr: GridRow[], val: number, start = 0, end = arr.length - 1): number {
    const mid = Math.floor((start + end) / 2);
    if (mid < 0)
        return 0;
    if (val === arr[mid].top)
        return mid;
    if (start >= end)
        return mid; // original version should return -1 if element dont exist
    return val < arr[mid].top
        ? rowBinarySearch(arr, val, start, mid - 1)
        : rowBinarySearch(arr, val, mid + 1, end);
}

预期行为: 1.删​​除上面评论列表中评论的hacky return 2. 找到第一个行的top 值低于搜索值的行 3. 如果不应该将lastIndex 增加1,我会很棒

感谢您的帮助:)

【问题讨论】:

  • 高度是否始终为 25,行是否始终相邻?
  • 25px 是默认行高,每行可能不同。是的,每一行都彼此相邻。

标签: javascript arrays typescript algorithm binary-search


【解决方案1】:
  1. 删除上面评论列表中评论的hacky return

这不是一个骇人听闻的回报。递归算法总是需要一个基本情况,start &gt;= end 正是这个递归所依赖的基本情况。

不是常规的是前面的return。如果val 允许所有整数值,那么val === arr[mid].top 是一种罕见的情况,实际上不需要特殊处理。想想当valarr[mid].top + 1 时会发生什么。它应该是相同的(假设 height 大于 1)。

mid &lt; 0 不是必需的时候,第一个return 也是如此,除非您打算使用startend 的负值调用此函数。实际上,您可能会在递归调用中为 end 执行此操作,但请参阅下一点,了解如何避免这种情况。

  1. 查找行的最高值低于搜索值的第一行

目前,您的算法不正确:当您在第二次调用中传递 120 而不是 140 时,返回值少 2 个单位,而您只能“爬”一行。

我建议将end 定义为当前范围之后 的第一个索引。这与为 .slice 等函数定义参数的方式是一致的。

  1. 如果不应该将 lastIndex 增加 1,我会很棒

您不应该努力这样做,因为如果您使用相同的函数来查找起始行和结束行,那么您希望选择比lastIndex - firstIndex 多一行是合乎逻辑的。所以加1就行了,不用担心。

这是一个固定的算法:

function rowBinarySearch(arr, val, start = 0, end = arr.length) {
    if (start >= end) return end - 1; // base case
    const mid = (start + end) >> 1; // Use shift, so you don't need to `floor`.
    return val < arr[mid].top
        ? rowBinarySearch(arr, val, start, mid)
        : rowBinarySearch(arr, val, mid + 1, end);
}

// Demo
const rows = Array.from({length: 7}, (_, id) => ({
    id, top: id*25, bottom: id*25+25, height: 25
}));
const firstIndex = rowBinarySearch(rows, 30);
const lastIndex = rowBinarySearch(rows, 140, firstIndex);
console.log(rows.slice(firstIndex, lastIndex + 1).map(JSON.stringify).join("\n"));

【讨论】:

  • 非常感谢!我在我的应用中实现了这个解决方案,效果很好。
猜你喜欢
  • 2014-07-10
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
  • 2014-03-02
  • 2013-10-22
  • 2014-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多