Document directory
I. Preface binary search is a simple algorithm, but it is because of its simplicity that it is easier to write errors. Even when the binary search algorithm emerged, there was a bug (an overflow bug) which was not fixed until decades later (see Programming pearl). This article aims to summarize the binary search algorithm and analyze and summarize the problems extended by binary search. If any error occurs, please do not hesitate to inform us. 2. Binary Search is a basic algorithm that everyone knows about binary search, as shown in the following figure. This is the binary search algorithm:
Int bisearch (int A [], int N, int t) // array a is ordered and the length is n. the value to be searched is t {int L = 0, U = n-1; while (L <= u) {int M = L + (u-l)/2; // same (L + u)/2, here is to overflow if (T> A [m]) L = m + 1; else if (T <A [m]) u = m-1; else return m ;} return-(L + 1 );}
The idea of the algorithm is that, starting from the middle of the array, half of the data is excluded each time, and the time complexity is O (lgn ).This depends on the order of arrays.If t exists in the array, t is returned in the array; otherwise,-(L + 1) is returned if T exists ). Here we need to explain why-(L + 1) is returned instead of-1 when t does not exist in the array ). First, we can observe the value of L. If the search fails, the value of L is exactly where T should be inserted in the array. For example, suppose that the ordered array A = {1, 3, 4, 7, 8}, then if T = 0, it is clear that t is not in the array, then the binary search algorithm will eventually cause l = 0> U =-1 to exit the loop. If t = 9, t is not in the array, then l = 5> U = 4 exits the loop. If t = 5, then l = 3> U = 2 to exit the loop. Therefore, in some algorithms, such as DHT (Consistent hash), this return value is required so that the newly added nodes can be inserted to a suitable position, this is also used in the nlgn Algorithm for Finding the longest incrementing subsequence. For more information, see the longest incrementing subsequence algorithm in the blog. Another small point is that-(L + 1) is returned instead of-l directly because l may be 0, if-L is returned directly, it cannot be determined whether the returned position is normal or the returned 0 is not successful. 3. the first occurrence of a number in binary search is now a slightly complex problem. If there are repeated numbers in an ordered array, such as an array A = {1, 2, 3, 3, 5, 7, 8}, you need to find the location where 3 appears for the first time. Here 3 is the first occurrence location of 2. This issue has been well analyzed in chapter 9 of "programming Pearl River" and is directly used here. The essence of an algorithm lies in the ingenious design of the loop without change. The Code is as follows:
Int bsearch_first (int A [], int N, int t) {int L =-1, u = N; while (L + 1! = U) {/* cycle-free a [l] <t <= A [u] & L <u */int m = L + (u-l)/2; // same as (L + u)/2 If (T> A [m]) L = m; else u = m;}/* assert: L + 1 = u & A [l] <t <= A [u] */int p = u; If (P> = n | A [p]! = T) P =-1; return P ;}
Algorithm Analysis: set two nonexistent elements, a [-1] and a [n], so that a [-1] <t <= A [n], but we will not visit two elements, because (L + u)/2> L =-1, (L + u)/2 <u = n. The cycle is L <u & T> A [l] & T <= A [u]. When a loop exits, L + 1 = U, and a [l] <t <= A [u]. After the loop exitsThe value of U is the possible location of T, and its range is [0, N].If t is in the array, the first position P = u appears. If not, P =-1 is set to return. Although the efficiency of this algorithm solves more complex problems, it is more efficient than the binary search in the initial version because it only needs to be compared once in each loop, the previous program usually needs to be compared twice. For example, for arrays A = {1, 2, 3, 3, 5, 7, 8}, if we look for t = 3, we can get p = u = 2, if you look for t = 4, a [3] <t <= A [4], so P = u = 4, judge a [4]! = T, so set P =-1. One exception is u> = n. For example, t = 9, then u = 7. In this case, set P =-1.
Note that L =-1, u = N values cannot be written as L = 0, u = n-1. Although these two values will not be accessed, if they are changed to the next one, the binary search will fail and the first number will not be accessed.For example, search for 1 in a = {1, 2, 3, 4, 5}. If l = 0, u = N-1 is set initially, the search fails.ExtensionWhat if I want to find the last position where the number appears in the array? In fact, this is similar to the above algorithm. You just need to modify the above algorithm. The Code is as follows:
Int bsearch_last (int A [], int N, int t) {int L =-1, u = N; while (L + 1! = U) {/* The loop is not variable, a [l] <= T <A [u] */int m = L + (u-l)/2; if (T> = A [m]) L = m; else u = m;}/* assert: L + 1 = u & A [l] <= T <A [u] */int p = L; If (P <=-1 | A [p]! = T) P =-1; return P ;}
Of course, there is also a way to write the code for the first occurrence and last occurrence of a query number in a program. You only need to slightly modify the original binary search. The Code is as follows:
Int binary_search_first_last (INT arr [], int P, int Q, int value, bool firstflag = true) {int begin = P; int end = Q; while (begin <= end) {int mid = (begin + end)/2; If (ARR [Mid] = value) // you can find the first or last occurrence. {If (firstflag) // query the first occurrence location {If (Mid! = P & arr [Mid-1]! = Value) return mid; else if (mid = P) return P; else end = mid-1;} else // query the last occurrence position {If (Mid! = Q & arr [Mid + 1]! = Value) return mid; else if (mid = q) return Q; else begin = Mid + 1 ;}} else if (ARR [Mid] <value) begin = Mid + 1; else end = mid-1;} return-1 ;}
Iv. Search for rotating array elements
Question:Moving the first several elements of an ordered array to the end of an array is called the rotation of an array. For example, an array {3, 4, 5, 1, 2} is a rotation of {1, 2, 3, 4, 5. Now the array and number after rotation are given, and the number of digits after rotation is unknown. An algorithm is required to calculate the subscript of the given number in the array. If this number is not found, -1 is returned. The number of searches cannot exceed n.
Analysis:As you can see, although the rotated array is unordered, the first and second parts are partially ordered. Therefore, binary search can be used to solve the problem.
Solution 1: 2 binary searches. First, determine the Split points of the array, that is, the arrays on both sides of the Split points are ordered. For example, the array in the example is separated by location 2. The previous part is {3, 4, 5} ordered, and the second part is {2, 2} ordered. Use binary search for the two parts. The Code is as follows:
Int split (int A [], int N) {for (INT I = 0; I <n-1; I ++) {if (a [I + 1] <A [I]) return I;} return-1;} int bsearch_rotate (int A [], int N, int T) {int P = Split (A, n); // locate the split position if (P =-1) return bsearch_first (A, N, t ); // if the original array is ordered, else {int left = bsearch_first (A, P + 1, t) can be directly searched in binary mode ); // find the left half if (Left =-1) {// The left half is not found, then find the right half int right = bsearch_first (a + p + 1, n-p-1, t); // search for the right half if (right! =-1) return right + p + 1; // return position. Add p + 1 return-1;} return left; // to the left half of the returned position, return directly }}
Solution 2: perform a binary search.
The binary search algorithm has two key points: 1) array order; 2) determine whether to perform the next binary search based on the relationship between the intermediate elements of the current interval and the size of X.
After carefully analyzing the problem, we can find that after finding the mid based on low and high, the left side of the mid ([low, mid]) and the right side ([mid, high]) at least one is ordered.
A [Mid] is compared with a [left] And a [right] respectively to determine which segment is ordered.
If the left side is ordered, if X <A [Mid] and x> A [left], Right = mid-1; otherwise, Left = Mid + 1;
If the right side is ordered, if X> A [Mid] and x <A [right], Left = Mid + 1; otherwise, Right = mid-1;
The Code is as follows:
Int bsearch_rotate (int A [], int N, int t) {int low = 0, high = n-1; while (low <= high) {int mid = low + (high-low)/2; If (t = A [Mid]) return mid; if (a [Mid]> = A [low]) {// left semi-ordered if (T> = A [low] & T <A [Mid]) High = mid-1; else low = Mid + 1 ;} else {// the right half of the array ordered if (T> A [Mid] & T <= A [High]) Low = Mid + 1; else high = mid-1 ;}} return-1 ;}
References
Binary Search programming for rotating Arrays