【问题标题】:Find closest index by difference with BinarySearch使用 BinarySearch 按差异查找最接近的索引
【发布时间】:2011-05-17 09:44:47
【问题描述】:

我有一个大约 500,000 个整数的排序数组。目前,我通过获取目标 int 和所有元素之间的差异来选择正确的索引,然后使用 LINQ 按最小差异排序(非常低效)。

我希望能够用 BinarySearch 做一些非常相似的事情。

给定:

Pos Value
0   10
1   20
2   30
4   50
5   60

如果我想找到值 24 的最接近值,我希望返回的索引为 1。

给定:

int index = myArray.BinarySearch(values, 24);
if (index < 0)
    index = ~index;

这将返回 2,因为它给出了行中的下一个元素,而不是最接近的。是否可以编写一个返回最近索引的 IComparer?

给定值:

Value ExpectedReturn
20    1
24    1
25    2
26    2
30    2

我正在尝试尽快完成此操作。到目前为止,我在 LINQ 中所做的一切都低于我认为通过出色的二进制搜索可以实现的目标。感谢您的意见。

【问题讨论】:

    标签: c# optimization binary-search


    【解决方案1】:

    只需进行二分搜索,如果结果是否定的,然后您找到将插入的位置并查看下一个 和上一个 条目 - 换句话说,使用您当前的代码,检查 @ 987654322@ 和 index - 1 (在检查 index 不是 0 之后:)。找出哪个更近,就完成了。

    【讨论】:

    • @Jon Skeet:+1,但答案无法编译,笑脸后缺少右括号。
    • 如何做到“你然后找到它会被插入的位置”高效,它可能需要搜索整个数组
    • @Saurabh:不,这正是BinarySearch 所做的——如果值已经存在,它会返回找到该值的索引,否则返回~insertionPoint
    • 补码后还需要一个if(index &gt;= myArray.Length) return myArray.Length - 1;。 “如果此索引大于或等于数组的大小,则数组中没有大于值的元素。” msdn.microsoft.com/en-us/library/2cy9f6wb.aspx
    • 哦,我忘记了问题中使用了 BinarySearch ...对不起,我的错误
    【解决方案2】:

    这是一个简短的演示,基于 John Skeet 的解释。 此方法仅返回介于 from Time 和 to Time 之间的日期。 它当然假设原始数组是按时间排序的。

    private DateTime[] GetDataForEntityInInterval(DateTime fromTime, DateTime toTime)
            {
    
            DateTime[] allValues = GetAllValuesFromDB();
            int indexFrom = Array.BinarySearch(allValues, fromTime);
    
             if(indexFrom < 0)
             {
                 int indexOfNearest = ~indexFrom;
    
                 if (indexOfNearest == allValues.Length)
                 {
                     //from time is larger than all elements
                     return null;
                 }
                 else if (indexOfNearest == 0)
                 {
                     // from time is less than first item
                     indexFrom = 0;
                 }
                 else
                 {
                     // from time is between (indexOfNearest - 1) and indexOfNearest
                     indexFrom = indexOfNearest;
                 }
             }
    
             int indexTo = Array.BinarySearch(allValues, toTime);
             if (indexTo < 0)
             {
                 int indexOfNearest = ~indexTo;
    
                 if (indexOfNearest == allValues.Length)
                 {
                     //to time is larger than all elements
                     indexTo = allValues.Length - 1;
                 }
                 else if (indexOfNearest == 0)
                 {
                     // to time is less than first item
                     return null;
                 }
                 else
                 {
                     // to time is between (indexOfNearest - 1) and indexOfNearest
                     indexTo = Math.Max(0, indexOfNearest - 1);
                 }
             }
    
            int length = indexTo - indexFrom + 1;
            DateTime[] result = new DateTime[length];
            if (length > 0)
            {
                Array.Copy(allValues, indexFrom, result, 0, length);
            }
            return result;
    
        }
    

    【讨论】:

    • +1 感谢您提供有用的示例。但是,我认为如果该示例实际回答了问题而不是查找 2 个 DateTimes 之间的时间,则可能会更清楚。
    猜你喜欢
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 2015-04-18
    • 2013-03-29
    • 2017-03-15
    • 1970-01-01
    相关资源
    最近更新 更多