そのため、バイナリ検索を実装できません。 私にとって、彼はささいなことではありません。 私は偽のプログラマーだと思います。 しかし、それは、私はただの学生ですが、これは言い訳ではありませんか? もっと正確に言えば、私は良い正しい美しいバイナリ検索を実装することはできません。 私は常に、正確さ、可愛さ、またはその両方で問題を抱えています。 それで、はい、タイトルは少し黄色がかっています。
このトピックを読む前に、ソート済み配列のバイナリ検索のバージョンを作成してください。 さらに、パラメータに応じて、検索は最初の要素または重複のいずれかを返す必要があります。 比較のために、関数のバイナリ検索を記述します
まず、C#でコードを記述します。 他の言語のファンが私のコードを簡単に理解できることを願っています。 検索の境界を半間隔として表します[左; 右)、つまり 左のポイントがオンになり、右のポイントがオフになります。 半分の間隔は私にとってより便利です。私はすでにその動作に慣れています。さらに、さまざまなアルゴリズムをプログラミングするときに、半分の間隔を使用するといくつかの利点があります(これについては後で説明します)。 一般に、次のようなループを記述するため、「統一プログラミングスタイル」をサポートするという点では、半間隔を使用する方が適切です。
for (int i = 0; i < array.Length; i++)
:for (int i = 0; i <= array.Length - 1; i++)
, , . :
static int BinarySearch_Rec_Wrapper(int[] array, int element)
{
BinarySearch_Rec(array, element, 0, array.Length);
}
, . , . , ,
int mid = (left + right) / 2
, (. ): int mid = left + (right - left) / 2
, . off-by-one. , :
, [0, 3) [4, 7), .. [left, mid) [mid + 1, right). , «» ( ), , , , . , , , , .
, : [left, right], [left, mid — 1] [mid + 1; right] ( , , ).
1 ( , ), — 2 — , .
, ( [left, mid) [mid, right)), 1 ( [left, mid] [mid + 1, right], [left, mid — 1] [mid, right]).
, , , , (array[mid]), (key). — , , , , :-). - . , , «».
:
static int BinarySearch_Rec(int[] array, int key, int left, int right)
{
int mid = left + (right - left) / 2;
if (array[mid] == key)
return mid;
else if (array[mid] > key)
return BinarySearch_Rec(array, key, left, mid);
else
return BinarySearch_Rec(array, key, mid + 1, right);
}
:
static int BinarySearch_Iter(int[] array, int key)
{
int left = 0;
int right = array.Length;
while (true)
{
int mid = left + (right - left) / 2;
if (array[mid] == key)
return mid;
if (array[mid] > key)
right = mid;
else
left = mid + 1;
}
}
:
, , , . while(true), , . , , . , ., , . - , ? - . ? ( , -1)? int int? null? (int? c# — , null). , - , ? - ? … , « ?». , , : , . , , , null, null.
-(1 + left), , , , . , — , . DRY, - , . , .
, left == right, .., — [left, right). , right — left < 1 right — left <= 0. , , , - ( , ).
:
static int BinarySearch_Rec(int[] array, int key, int left, int right)
{
int mid = left + (right - left) / 2;
if (left >= right)
return -(1 + left);
if (array[mid] == key)
return mid;
else if (array[mid] > key)
return BinarySearch_Rec(array, key, left, mid);
else
return BinarySearch_Rec(array, key, mid + 1, right);
}
:
static int BinarySearch_Iter(int[] array, int key)
{
int left = 0;
int right = array.Length;
int mid = 0;
while (!(left >= right))
{
mid = left + (right - left) / 2;
if (array[mid] == key)
return mid;
if (array[mid] > key)
right = mid;
else
left = mid + 1;
}
return -(1 + left);
}
:
, . , , . , - , .№3
, . ||, &&, , XOR':
descendingOrder | array[mid] > key | XOR |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
.. descendingOrder , , , . «», , - . , .
:
static int BinarySearch_Rec(int[] array, bool descendingOrder, int key, int left, int right)
{
int mid = left + (right - left) / 2;
if (left >= right)
return -(1 + left);
if (array[mid] == key)
return mid;
else if ((array[mid] > key) ^ descendingOrder)
return BinarySearch_Rec(array, descendingOrder, key, left, mid);
else
return BinarySearch_Rec(array, descendingOrder, key, mid + 1, right);
}
static int BinarySearch_Rec_Wrapper(int[] array, int key)
{
if (array.Length == 0)
return -1;
bool descendingOrder = array[0] > array[array.Length - 1];
return BinarySearch_Rec(array, descendingOrder, key, 0, array.Length);
}
:
static int BinarySearch_Iter(int[] array, bool descendingOrder, int key)
{
int left = 0;
int right = array.Length;
int mid = 0;
while (!(left >= right))
{
mid = left + (right - left) / 2;
if (array[mid] == key)
return mid;
if ((array[mid] > key) ^ descendingOrder)
right = mid;
else
left = mid + 1;
}
return -(1 + left);
}
static int BinarySearch_Iter_Wrapper(int[] array, int key)
{
if (array.Length == 0)
return -1;
bool descendingOrder = array[0] > array[array.Length - 1];
return BinarySearch_Iter(array, descendingOrder, key);
}
:
: , . .№4
, . «» — , . , , … .
, , :
, , , . , , . , , . (. )
:
static int BinarySearch_Rec(int[] array, bool descendingOrder, int key, int left, int right)
{
int mid = left + (right - left) / 2;
if (left >= right)
return -(1 + left);
if (array[left] == key)
return left;
if (array[mid] == key)
{
if (mid == left + 1)
return mid;
else
return BinarySearch_Rec(array, descendingOrder, key, left, mid + 1);
}
else if ((array[mid] > key) ^ descendingOrder)
return BinarySearch_Rec(array, descendingOrder, key, left, mid);
else
return BinarySearch_Rec(array, descendingOrder, key, mid + 1, right);
}
static int BinarySearch_Rec_Wrapper(int[] array, int key)
{
if (array.Length == 0)
return -1;
bool descendingOrder = array[0] > array[array.Length - 1];
return BinarySearch_Rec(array, descendingOrder, key, 0, array.Length);
}
:
static int BinarySearch_Iter(int[] array, bool descendingOrder, int key)
{
int left = 0;
int right = array.Length;
int mid = 0;
while (!(left >= right))
{
mid = left + (right - left) / 2;
if (array[left] == key)
return left;
if (array[mid] == key)
{
if (mid == left + 1)
return mid;
else
right = mid + 1;
}
else if ((array[mid] > key) ^ descendingOrder)
right = mid;
else
left = mid + 1;
}
return -(1 + left);
}
static int BinarySearch_Iter_Wrapper(int[] array, int key)
{
if (array.Length == 0)
return -1;
bool descendingOrder = array[0] > array[array.Length - 1];
return BinarySearch_Iter(array, descendingOrder, key);
}
№5
, , , , . , , :
?
?
enum ElementToChoose
{
First,
Last,
NoCare
}
/// <summary>
/// Finds element equal to value in sorted array in range [low, high)
/// </summary>
static int binarySearch(int value, int[] array, bool ascendingOrder, ElementToChoose elementToChoose, int low, int high) {
// return valid invalid position
if (low >= high)
return -(low + 1);
// return first or last found element
if (elementToChoose == ElementToChoose.First)
if (value == array[low])
return low;
int last = high - 1;
if (elementToChoose == ElementToChoose.Last)
if (value == array[last])
return last;
int mid = low + (high - low) / 2;
// we have found some element
if (value == array[mid]) {
switch (elementToChoose) {
case ElementToChoose.NoCare:
return mid;
case ElementToChoose.First:
if (mid - low <= 1)
// array[mid] is the earliest element in array, return it
// because array[low] != value && array[low+1] == value, where mid == low + 1
return mid;
else
// try to find first element
// don't forget to capture current element {|0, 0|, 1} -> {0, 0}
return binarySearch(value, array, ascendingOrder, elementToChoose, low, mid + 1);
case ElementToChoose.Last:
if (last - mid <= 1)
// array[mid] is the last element in array, return it
// because array[last] != value && array[last - 1] == value, where mid == last - 1
return mid;
else
// try to find last element
// don't forget to capture current element {0, |0, 1|} -> {0, 1}
return binarySearch(value, array, ascendingOrder, elementToChoose, mid, high);
}
}
// choose left or right half, depending on sorting order & comparing value and mid
if ((value < array[mid]) ^ !ascendingOrder)
return binarySearch(value, array, ascendingOrder, elementToChoose, low, mid);
else
return binarySearch(value, array, ascendingOrder, elementToChoose, mid + 1, high);
}
, ? , 3 , ? , , , ( ).
, , / getFirstHalf, getSecondHalf ( ), getStartPoint/getLastPoint ( / ), increaseLength/decreaseLength ( ), moveStartPoint. - . , .
, , . … , « », . :
// - Func<float, float> , float float
static float BinarySearch_Func(Func<float, float> func, bool descendingOrder, float key, float left, float right)
{
float mid = (left + right) / 2;
if (left == mid || mid == right)
return mid;
if ((func(mid) > key) ^ descendingOrder)
return BinarySearch_Func(func, descendingOrder, key, left, mid);
else
return BinarySearch_Func(func, descendingOrder, key, mid, right);
}
static float BinarySearch_Func_Wrapper(Func<float, float> func, float key, float left, float right)
{
if (left > right)
return float.NaN;
bool descendingOrder = func(left) > func(right);
bool isOk = true;
if (!descendingOrder)
isOk = func(left) <= key && key <= func(right);
else
isOk = func(right) <= key && key <= func(left);
if (isOk)
return BinarySearch_Func(func, descendingOrder, key, left, right);
else
return float.NaN;
}
. ? ? float'? ( , ?, , - ).
? left; right? [left, right], [left, right), (left, right], (left, right)? . :
// x => x - - f(x) = x
Console.WriteLine(BinarySearch_Func_Wrapper(x => x, 0.7f, 0.7f, 100.0f)); // : 0.7
Console.WriteLine(BinarySearch_Func_Wrapper(x => x, 0.8f, 0.8f, 100.0f)); // : 0,8000001
Console.WriteLine(BinarySearch_Func_Wrapper(x => x, 0.9f, 0.9f, 100.0f)); // : 0,9
Console.WriteLine("{0:0.00000000}",0.8f); // : 0,80000000
, left . right (). .. a b, a, b, - . .
, , , mid /. .
- , func(left) == key func(right) == key, .
, : , .
, , - . , - .
, - , : , — , a/b. : a b . -: O(lgn).
, : - — , // , , ?
P.S: , . ,
P.P.S: ?
UPD1: fox_anthony -(1 + left) ~left. : ~, msdn, c#