题:比如说在A[] = {7, 8, 1, 2, 3, 4, 5, 6};查找元素。A是由{1, 2, 3, 4, 5, 6, 7, 8}左旋6位得到。
假定数组旋转前是有序递增的,且没有重复的元素。
方法:二分查找,再分情况讨论。在确定l, m, r后,旋转后的数组有图1所示的四种情况,且对应的元素有图2所示的关系。
由图中可以看出,根据A[l]与A[r]的大小关系可以区分出第4种情况。然后根据A[l]与A[m]的关系可以区分出第1中情况。
第2和第3中情况难以区分,但是如果
(1)m == r,肯定是第2种情况(或第4种情况,当然第4种情况右侧元素个数为0的话也退化成第2种情况)
(2)否则m < r,m+1在检查的范围之内,是有意义的
1)如果A[m] > A[m + 1]则是第2种情况
2)否则A[m] < A[m + 1]是第3种情况
对于第4和第2种情况,简单的调用通用的二分查找函数即可。
对于第1种情况,如果确定要查找的值在A[m+1:r]的范围内,可以调用简单的二分查找函数,否则对A[l:m+1]继续上面的情况分类。
对于第3种情况,讨论与第1种情况类似。
程序如下
- #include <iostream>
- #include <iomanip>
- #include <cstdlib>
- #include <ctime>
- using namespace std;
- static void left_rotate_1(int A[], const int N)
- {
- int tmp = A[0];
- for (int i = 0; i < N - 1; i++){
- A[i] = A[i + 1];
- }
- A[N - 1] = tmp;
- }
- static int binary_search(const int A[], int l, int r, const int val)
- {
- int m;
- while (l <= r){
- m = (l + r) >> 1;
- if (val == A[m])
- return m;
- else if (val < A[m])
- r = m - 1;
- else
- l = m + 1;
- }
- return -1;
- }
- static int rotated_search(const int A[], const int N,
- const int val)
- {
- int l, r, m;
- l = 0;
- r = N - 1;
- cout << "searching " << val << endl;
- while (l <= r){
- m = (l + r) >> 1;
- if (A[l] < A[r]){
- /*case 4*/
- return binary_search(A, l, r, val);
- }
- if (val == A[m])
- return m;
- else if (A[l] > A[m]){
- /*case 1*/
- if (val > A[m] && val <= A[r])
- return binary_search(A, m + 1, r, val);
- else
- r = m - 1;
- }else{
- /*case 2 and 3*/
- if (m == r || A[m] > A[m + 1]){
- /*case 2*/
- l = binary_search(A, l, m - 1, val);
- if (-1 != l)
- return l;
- return binary_search(A, m + 1, r, val);
- }else{
- /*case 3*/
- if (val >= A[l] && val < A[m]){
- return binary_search(A, l, m - 1, val);
- }else{
- l = m + 1;
- }
- }
- }
- }
- return -1;
- }
- static inline void case_test(const int val)
- {
- cout << "get" << setw(5) << val << endl;
- }
- static void print_array(const int A[], const int N)
- {
- cout << "index:";
- for (int i = 0; i < N; i++){
- cout << setw(5) << i;
- }
- cout << endl;
- cout << "array:";
- for (int i = 0; i < N; i++){
- cout << setw(5) << A[i];
- }
- cout << endl;
- }
- static int int_compare(const void *p1, const void *p2)
- {
- return (*(const int *)p1 - *(const int *)p2);
- }
- int main()
- {
- const int N = 8;
- int A[N] = {4, 4, 5, 6, 7, 2, 3, 4};/* = {6, 1, 5, 5, 5, 3, 6, 4};*/
- srandom((unsigned int)time(NULL));
- print_array(A, N);
- case_test(rotated_search(A, N, 5));
- for (int i = 0; i < N; i++)
- A[i] = random() % N;
- qsort(A, N, sizeof(int), int_compare);
- print_array(A, N);
- case_test(rotated_search(A, N, 3));
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- left_rotate_1(A, N);
- print_array(A, N);
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- left_rotate_1(A, N);
- left_rotate_1(A, N);
- print_array(A, N);
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- case_test(rotated_search(A, N, random() % N));
- return 0;
- }