Reprint Address: http://www.cnblogs.com/ider/archive/2012/04/01/binary_search.html
Realization and application Summary of binary search method
In the process of learning the algorithm, in addition to understand the basic principle of an algorithm, the implementation of the way, the more important part is the use of big-o theory to analyze the complexity of the algorithm. In time complexity and space complexity, we will pay more attention to the complexity of time.
The complexity of time is almost concentrated in the following advantages and disadvantages:
O (1), O (log n), O (n), O (n log n), O (N2), O (NK), O (2n)
To the current position, it seems that the algorithm that I learned, the time complexity is O (log n), as if the number of binary lookup method, other such as the sorting algorithm is O (n log n) or O (N2). But it is also because of the binary O (log n) that many O (N2) have been reduced to just O (n log n).
On the binary search method
The binary search method mainly solves the problem of "finding the specified number in a pile number".
To apply a binary lookup method, this "pile number" must have a feature:
- stored in the array
- Orderly arrangement
So if you are using a linked list, you cannot apply a binary lookup method on it. (Ozone in the interview is asked what data structures can be used on the binary lookup method: arrays? Linked list? )
It does not matter whether the same elements exist in the array if the order is ascending or descending. In general, however, we hope and assume that the arrays are ascending and that the elements in the array are different.
The basic realization of binary search method
The binary search method belongs to "divide and conquer" in the large class of the algorithm family, and the method of division and treatment can be realized by recursion, and the recursive realization of the binary search method is as follows:
int bsearch (int array[],int Low, int High, int Target)
{
if (Low > High) return-1;
int mid = (low + high)/2;
if (array[mid]> target)
return BinarySearch (Array, low, mid-1, Target);
if (array[mid]< target)
return BinarySearch (Array, Mid+1, high, target);
//if (Midvalue = = target)
return mid;
}
However, all recursion can be self-defined stack to solve recursion, so the binary lookup method can also be implemented without recursion, and its non-recursive implementation can even use no stack, because the recursion is actually the tail recursion, it does not care about all the information before recursion.
int Bsearchwithoutrecursion (int array[],int Low,int High,int target)
{
while (Low <= high)
{
int mid = (low + high)/2;
if (Array[mid] > target)
High = mid- 1;
Else if (Array[mid] < target)
Low = mid + 1;
Else /Find the target
return mid;
}
//Thearray does not contain the target
return-1;
}
Binary lookup method with less than comparison (<)
In the previous binary lookup implementations, we used either a less than comparison (<) and a greater than comparison (>), and might also need an equality comparison (= =).
And actually we just need a less than comparison (<) on it. A>b and B<a should have a logical value because of the wrong logic, while a==b is equivalent to! ((a<b) | | (B<a)), that is, a is neither less than B, nor much more than B.
Of course, in the program world, this relationship logic is not exactly right. In addition, C + + allows overloading of objects with operators, so developers are free to design and implement the logical values of these relational operators at will.
However, in the face of integer data, the logical relationship between these operators is still established, and in the development process, we will still follow these logical equivalence relations to overload the relational operator.
Why do you have to be so shy, just use a relational operator? This allows you to write a template for the two-point lookup method, and to reduce the requirement for the target object. The template will be like this:
Template <typename T, TypeName v>
Inlineint bsearch (t& array,int Low,int high, v& target)
{
while (! ( )
{
int mid = (low + high)/2;< br> if (Target < Array[mid])
High = mid-1;
Span style= "color: #0000ff;" >else if (Array[mid] < target)
Low = mid + 1;
Span style= "color: #0000ff;" >else //find the Target return mid;
}
//the array does not contain the Target
return-1;
} /span>
We just need to ask the target type V to have overloaded less than the operator. For the set type T of V, an overload of the [] operator is required. Of course, its internal implementation must be O (1) complexity, otherwise it will lose the efficiency of the two-point lookup.
Finding boundary value by binary search method
The previous one was to find a number in the array to be equal to the target, and return 1 if it did not exist. We can also use the binary lookup method to find the boundary value, that is, in an ordered array of "exactly greater than (less than) the number of targets" the number.
In mathematical terms, the expression is:
A number x is found in the collection that is greater than (less than) the number of targets T, so that any number in the collection is either greater than (less than) equal to X, or less than (greater than) equal to T.
For example:
Given array and target number
int array = {17};
7;
Then the upper bound value should be 11, because it is "just good" greater than 7, and the next value is 5 because it is "just good" less than 7.
Finding the last of the past with the binary search method
//Find the fisrt element, whose value is larger than target, in a sorted array
int Bsearchupperbound (int array[],int Low,int High, int target)
{
//array is empty or target was larger than any every element I N array
if (Low > High | | target >= Array[high]) Span style= "color: #0000ff;" >return-1;
int mid = (low + high)/while (High > Low)
{
if (Array[mid] > target)
High = mid;
else
Low = mid + 1;
Mid = (low + high)/2;
}
return mid;
}
Unlike exact lookups, exact lookups fall into three categories: greater than , less than , equal to (target number). The boundary search is divided into two categories: greater than and less than.
If the currently found number is greater than the target number, it may be the number we are looking for, so we need to keep this index, and therefore if (Array[mid] > target) high=mid; And not minus 1.
find the next session with a binary search method
//Find the last element, whose value was less than target, in a sorted array
int Bsearchlowerbound (int array[],int Low,int High,int target)
{
//Array is empty or the target is less than any every element in array
if (High < low | | target <= array[low]) return-1;
int mid = (low + high + 1)/ 2; //Makemid lean to large side
While (Low < High)
{
if (Array[mid] < target)
Low = mid;
Else
High = mid- 1;
Mid = (low + high + 1)/ 2;
}
return mid;
}
The next search is basically the same as the previous one, and it is important to note that when you take an intermediate index, you use an upward rounding. If the downward rounding is used as before, then a dead loop is formed when the low = = High-1, while the Array[low] is less than the target. Because low cannot climb upwards above high.
Both implementations are looking for strict boundaries , that is, to be greater than or less than. If you want to find loose bounds, that is, to find a value greater than or equal to or less than equals (that is, include itself), just a little modification of the code is fine:
Remove the equals sign that determines the bounds of the array:
Target >= Array[high] change to target > Array[high]
Add an equal sign to the middle value comparison:
Array[mid] > Target to Array[mid] >= target
Finding the area with the binary search method
Before we used the binary lookup method, it was all based on the different elements in the array . If there is duplicate data, and the array is still orderly, then we can still use the binary search method to determine whether the target number exists. However, the index returned can only be one of the random repeating data.
At this point, we will want to know how many target numbers exist. Or we want the area of the array.
In combination with the previous boundary search, we only need to find the target number of the strict last and strict next, then the boundary (excluding the boundary) data is the area of the target number.
//Return Type:pair<int, int>
//The fisrt value indicate the begining of range,
//The second value indicate the end of range.
//If Target is not find, ( -1,-1) 'll be returned
pair<IntInt> Searchrange (int a[],int N,int target)
{
pair<IntInt> R (-1,-1);
if (n <=0)return R;
int lower = Bsearchlowerbound (A,0, N-1, target);
Lower = lower +1;//Move to next element
if (a[lower] = = target)
R.first = lower;
Else//target is not in the Array
return R;
int upper = Bsearchupperbound (A, 0, N-1, Target);
Upper = Upper < 0? (N-1):(upper-1); //move to previous element
//since in previous search we had check whether the target is
//in the array or not, we don't need to check it here Again< br> R.second = Upper;
return R;
}
Its time complexity is the same as the time spent searching two times, that is, O (log n) + O (log n), and finally O (log n).
Applying the binary search method to the ordered array after rotation
Before we said that the dichotomy is to be applied to an ordered array, and if it is unordered, then the comparison and the dichotomy are meaningless.
But there is also a special kind of array that can also be applied, that is, "after the rotation of the ordered array (rotated Sorted array)". It is an ordered array, taking a number in the middle of the axis, and all its previous numbers are rotated to the end of the array. For example {7, 11, 13, 17, 2, 3, 5} is an ordered array after rotation. In the non-strictly sense, ordered arrays also belong to the ordered array after rotation-we take the first element as the axis rotation.
Below is the implementation of the binary lookup method on an ordered array after rotation (assuming that the same element does not exist in the array)
int Searchinrotatedsortedarray (int array[],int Low,int High,int target)
{
while (Low <= high)
{
int mid = (low + high)/2;
if (Target < Array[mid])
if (Array[mid] < Array[high])//The higher part is sorted
High = mid-1;//The target would only is in lower part
Else//The lower part is sorted
if (Target < Array[low])//The target is less than all elements
Low = mid +1;
Else
High = mid-1;
Elseif (Array[mid] < target)
if (Array[low] < Array[mid])//The lower part is sorted
Low = mid +1;//The target would only is in higher part
else //the higher part is Sorted
if (Array[high) < target ) //the target is larger than all elements in higher part< Span style= "color: #008000;" >
High = mid-1;
else
Low = mid + 1;
else //if (Array[mid] = = target)
return mid;
}
return-1;
}
In contrast to the normal binary search method, we need more criteria for determining the number of targets that fall in the second part of the division. But we have achieved the goal of O (log n).
The defect of binary search method
The binary lookup method of O (log n) makes it a very efficient algorithm. But its flaws are so obvious. On top of its limits:
must shall be orderly , it is difficult to guarantee that our arrays are orderly. Of course, you can sort the array when you build it, but it falls to the second bottleneck: it must be an array.
Array read efficiency is O (1), but its efficiency in inserting and deleting an element is O (n). This results in the construction of an ordered array into inefficient things.
The better way to solve these defects is to use a two-fork search tree, preferably a self-balancing binary search tree, which is self-efficient (o (n log n)) to construct an ordered set of elements, and can be as fast as a binary lookup (O (log n)) search target number.
Implementation and application summary of binary search (reprint)