首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >二分多重搜索

二分多重搜索
EN

Stack Overflow用户
提问于 2018-11-30 19:41:26
回答 3查看 126关注 0票数 0

我想要得到(8)的所有位置,像这样的数组:(3,5,6,7,8,8,8,9,33,34,45)。但是我的代码只返回一个位置,而忘记了第二个位置:

这是我的二进制搜索代码:

代码语言:javascript
复制
private static int BinarySearch(int[] array, int item)
{
    int left = 0;
    int right = array.Length - 1;

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

        if (array[middle] == item)
            return middle;

        if (item < array[middle])
            right = middle - 1;
        else
            left = middle + 1;
    }

    return -1;
}
EN

回答 3

Stack Overflow用户

发布于 2018-11-30 20:03:49

你想要的和C++ "equal_range()" method是一样的。

看看标准的C++实现,它们使用"lower_bound()“查找低值,使用"upper_bound”查找高值。它是这样做的,而不是对从普通二进制搜索中找到的索引进行“扫描”,以确保它始终在O(Log(N))时间刻度内工作。对边界的线性搜索可能退化为O(Log(N))操作,然后是O(N)操作。

下面是C++的lower_bound()upper_bound()equal_range()的C#实现

代码语言:javascript
复制
public static class BoundedSearch
{
    /// <summary>Same as C++'s equal_range()</summary>

    public static Tuple<int, int> EqualRange<T>(IList<T> values, T target) where T : IComparable<T>
    {
        int lowerBound = LowerBound(values, target, 0, values.Count);
        int upperBound = UpperBound(values, target, lowerBound, values.Count);

        return new Tuple<int, int>(lowerBound, upperBound);
    }

    /// <summary>Same as C++'s lower_bound()</summary>

    public static int LowerBound<T>(IList<T> values, T target, int first, int last) where T : IComparable<T>
    {
        int left  = first;
        int right = last;

        while (left < right)
        {
            int mid = left + (right - left) / 2;
            var middle = values[mid];

            if (middle.CompareTo(target) < 0)
                left = mid + 1;
            else
                right = mid;
        }

        return left;
    }

    /// <summary>Same as C++'s upper_bound()</summary>

    public static int UpperBound<T>(IList<T> values, T target, int first, int last) where T : IComparable<T>
    {
        int left = first;
        int right = last;

        while (left < right)
        {
            int mid = left + (right - left) / 2;
            var middle = values[mid];

            if (middle.CompareTo(target) > 0)
                right = mid;
            else
                left = mid + 1;
        }

        return left;
    }
}       

(注意:此代码使用旧的Tuple<>类返回范围。如果您使用的是最新版本的C#和.Net,则可以将其更改为返回适当的元组(如public static (int LowerBound, int UpperBound) EqualRange<T>(...))。

票数 3
EN

Stack Overflow用户

发布于 2018-11-30 21:55:55

正如马特在评论中暗示的那样,你可以返回一个IEnumerable<int>,返回以下值:

代码语言:javascript
复制
private static IEnumerable<int> BinarySearch(int[] array, int item)
{
    int left = 0;
    int right = array.Length - 1;

    while (left <= right)
    {
        if (array[left] == item)
            yield return left;

        if (left == right)
            break;

        if (array[right] == item)
            yield return right;

        left++;
        right--;
    }
}

您可以按如下方式使用它:

代码语言:javascript
复制
static void Main(string[] args)
{
    var items = new int[] { 3, 5, 6, 7, 8, 8, 9, 33, 34, 45, 8 };

    foreach (var item in BinarySearch(items, 8))
    {
        Console.WriteLine(item);
    }
}

或者物化一个数组或列表,如果你想这样做的话:

代码语言:javascript
复制
static void Main(string[] args)
{
    var items = new int[] { 3, 5, 6, 7, 8, 8, 9, 33, 34, 45, 8 };

    var results = BinarySearch(items, 8).ToArray();
}
票数 1
EN

Stack Overflow用户

发布于 2018-11-30 20:02:36

您将返回一个int。这只是一个位置。您可能需要更改代码以返回一个数组:int[],也可以在其中执行return middle;您应该在middle之前和之后搜索所有匹配值。这可以是一个线性搜索,以保持它的简单性,或者如果您希望有大量的匹配值,它也可以是二进制的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53556854

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档