【问题标题】:binary search nearest match with last occurrence二分查找与最后一次匹配最近的匹配
【发布时间】:2015-01-23 09:05:02
【问题描述】:

我正在实施有效的算法来搜索(键或最近匹配(上限))的最后一次出现。

到目前为止,我得到了这个。

long bin_search_closest_match_last_occurance ( long  * lArray, long sizeArray, long lnumber)
{
    long left, right, mid, last_occur;

    left = 0;
    right = sizeArray - 1;
    last_occur = -1;

    while ( left <= right )
    {
        mid = ( left + right ) / 2;

        if ( lArray[mid] == lnumber  )
        {
            last_occur = mid;
            left = mid +1;
        }

        if ( lArray[mid] > lnumber ) 
            right = mid - 1;
        else 
            left = mid + 1;
    }
    return last_occur!=-1?last_occur:mid;
}

让我们有一个数组{0,0,1,5,9,9,9,9},键是6 fce 应该返回索引7,但我的 fce 返回4

请注意,我不想线性迭代到最后一个匹配索引。

请记住,我有解决方案,我更改参数 fce(添加开始,结束索引)并使用 fce 从找到的上限到数组末尾进行另一次二进制搜索(仅当我找不到完全匹配时,last_occur==-1) .

我想问是否有更好/更清洁的解决方案来实现它?

【问题讨论】:

  • 不确定为什么它应该返回 7。它要求找到键的最后一次出现,或者最接近的匹配,所以如果键不在列表中(这是你的例子) - 返回 4 应该没问题,因为我理解任务描述。
  • @amit 编辑了这个问题。现在应该更清楚了
  • 你在 while 指令之后打开一个 { 并且你永远不会关闭它。
  • @DanielDaranas 是的,对不起,错字
  • 我不知道它为什么有用,但解决方案是运行两次上界搜索。

标签: c algorithm binary-search upperbound last-occurrence


【解决方案1】:

nm 的 2 次搜索方法会起作用,并且它会保持最佳时间复杂度,但如果从第一次搜索结束的位置开始第二次搜索,它可能会将常数因子增加约 2 或约 1.5。

如果您采用“普通”二分搜索找到lnumber第一个 实例(或者,如果它不存在,则为下限),并更改它以使算法通过将每个数组访问 lArray[x] 更改为 lArray[sizeArray - 1 - x](对于任何表达式 x)在逻辑上“反转”数组,并通过将 &gt; lnumber 测试更改为 &lt; lnumber 来“反转”排序,然后 只需要一次二分搜索。该算法实际执行的唯一数组访问是对lArray[mid] 的两次查找,优化编译器很可能只评估一次,如果它可以证明访问之间的值不会改变(这可能需要将restrict 添加到long * lArray 的声明;或者,您可以将元素加载到局部变量中并测试两次)。无论哪种方式,如果每次迭代只需要一个数组查找,那么将索引从 mid 更改为 sizeArray - 1 - mid 每次迭代只会添加 2 个额外的减法(或者如果您在进入循环之前 --sizeArray 则只添加 1 个),这我预计不会像 nm 的方法那样增加常数。当然,与任何事情一样,如果性能很关键,那么就对其进行测试;如果不是,那么不要太担心节省微秒。

您还需要“反转”返回值:

return last_occur!=-1?last_occur:sizeArray - 1 - mid;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-25
    相关资源
    最近更新 更多