【问题标题】:Binary multi search二进制多重搜索
【发布时间】:2019-05-02 13:39:23
【问题描述】:

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

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

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;
}

【问题讨论】:

  • 您返回的是int。这只是一个位置。您可能需要更改代码以返回数组:int[]
  • 也许你可以用Yield做一些花哨的事情
  • @ikerbera 这将是不必要的 - 因为它是二进制搜索,我们可以假设数据已排序......所以我们真正需要的是一个索引/计数对;注意:无论如何,现有代码实际上是错误的......当找到一个匹配时,它应该做两件事:向后走找到 first 匹配,并向前走找到最后一个/count
  • return middle; 的位置,您应该搜索beforeafter middle 的所有匹配值。这可能是线性搜索以保持简单,或者如果您期望可能有很多匹配值,它可能是二进制的。
  • 为什么答案被删除了?其中至少有一个有效。

标签: c# binary-search


【解决方案1】:

你想要的和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# 实现:

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&lt;&gt; 类来返回范围。如果您使用的是最新版本的 C# 和 .Net,则可以将其更改为返回正确的元组,例如 public static (int LowerBound, int UpperBound) EqualRange&lt;T&gt;(...))。

【讨论】:

    【解决方案2】:

    正如 Matt 在 cmets 中暗示的那样,您可以返回 IEnumerable&lt;int&gt;,yield 返回值:

    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--;
        }
    }
    

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

    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);
        }
    }
    

    或者如果你想预先实现一个数组或列表:

    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();
    }
    

    【讨论】:

      【解决方案3】:

      您返回的是int。这只是一个位置。您可能需要更改代码以返回数组:int[] 还有您在哪里做return middle;您应该搜索middle 之前和之后的所有匹配值。这可能是线性搜索以保持简单,或者如果您期望可能有很多匹配值,它可能是二进制搜索。

      【讨论】:

      • 怎么样?你能给我正确的编辑吗?我试过了,但有解决方案
      • 简单来说,您可以代替返回中间将其添加到数组中,最后返回该数组
      猜你喜欢
      • 2020-08-23
      • 1970-01-01
      • 2020-11-16
      • 2020-02-28
      • 2014-07-10
      • 2014-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多