对于区间[a,b]上连续不断且f(a)·f(b)<0的函数y=f(x),通过不断地把函数f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点。
适用于提高大列表查询速度,对于包含n个元素的列表,时间复杂度为:O(log2n)。
列表必须有序,并且当列表中存在多个相同元素时并非返回列表中第一次出现元素,不同实现算法获取到元素索引也不一定相同。
-
代码实现1
/// <summary>
/// 递归实现元素查找
/// <para>集合长度不变,左右查找边界移动。</para>
/// <para>已经做集合有序性检查,必须升序,否则返回-1</para>
/// <para>集合中存在查找元素时返回索引,否则返回-1。</para>
/// </summary>
/// <param name="list">查找集合</param>
/// <param name="t">待查找元素</param>
/// <param name="left">查找左边界</param>
/// <param name="right">查找右边界</param>
/// <returns></returns>
static int FindIndexByBisection(List<int> list, int t, int left, int right)
{
/*保证集合有序*/
if (list[left] > list[right])
return -1;
/*集合中存在的元素一定在最小值与最大值之间*/
if (t < list[left] || t > list[right])
return -1;
/*左右边界已经首次靠近,但是两边界所在元素均不等于待查找元素,直接返回*/
if (right - left == 1 && list[left] != t && list[right] != t)
return -1;
int midIndex = (left + right) / 2;
int midValue = list[midIndex];
if (t < midValue)
return FindIndexByBisection(list, t, left, midIndex);
else if (t > midValue)
return FindIndexByBisection(list, t, midIndex, right);
else
return midIndex;
}
-
代码实现2
/// <summary>
/// 递归实现元素查找
/// <para>集合长度变化,左右查找边界固定。</para>
/// <para>已经做集合有序性检查,必须升序,否则返回-1。</para>
/// <para>集合中存在查找元素时返回索引,否则返回-1。</para>
/// </summary>
/// <param name="list">查找集合</param>
/// <param name="t">待查找元素</param>
/// <param name="index">待查找元素索引</param>
static void FindIndexByBisection(List<int> list, int t, ref int index)
{
/*初始值处理,防止调用方法中设置了错误默认值*/
int count = list.Count;
int midIndex = count / 2;
int midValue = list[midIndex];
/*找到元素立即返回*/
if (t == midValue)
{
index += 1;
return;
}
/*未找到元素,且集合长度变为1返回-1*/
if (list.Count == 1)
{
index = -1;
return;
}
/*未找到元素,集合长度大于1,但集合无序返回-1*/
if (list[count - 2] > list[count - 1])
{
index = -1;
return;
}
List<int> midList = list.Take(midIndex).ToList();
if (t > midValue)
{
index += midIndex;//元素比集合中间位置元素大时将中间元素索引累加上去
midList = list.Skip(midIndex).ToList();
}
FindIndexByBisection(midList, t, ref index);
}