我想获得(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;
}
答案 0 :(得分:3)
您想要的与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<>
类返回范围。如果您使用的是C#和.Net的最新版本,则可以将其更改为返回正确的元组,例如public static (int LowerBound, int UpperBound) EqualRange<T>(...)
)。
答案 1 :(得分:2)
正如马特在评论中暗示的那样,您可以返回IEnumerable<int>
,并返回值:
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();
}
答案 2 :(得分:0)
您要返回int
。那只是一个位置。您可能需要更改代码以返回数组:int[]
也在您的地方return middle
;您应该搜索middle
之前和之后的所有匹配值。为了简单起见,这可能是一个线性搜索,或者,如果您期望潜在的大量匹配值,它可能是二进制形式。