public class Test {
    // 已知数组A是由有序数组B(数组B未知)向右移动n(0<=n<=B.length)位得到
    // 例如 A = {4, 5, 1, 2, 3} 由 B = {1, 2, 3, 4, 5} 向右移动2位得到
    // 求在数组A中搜索元素x

    private static int search(int[] a, int h, int t, int x) {
        if (h > t) return -1;
        int result = -1;
        int mid = (h + t) / 2;
        if (a[mid] == x) return mid;
        if (a[h] == a[t] && a[h] == a[mid]) {
            // 这种情况无法判断哪边是递增,那边是旋转数组,如下
            // a = {5, X, 5, X, 5}
            // a = {5, 5, 5, 6, 5}
            // a = {5, 6, 5, 5, 5}
            result = search(a, h, mid - 1, x);
            if (result == -1) result = search(a, mid + 1, t, x);
        } else if (a[h] < a[t]) {
            result = binarySearch(a, h, t, x);
        } else {    // a[h] > a[t] || ( a[h] == a[t] && a[h] != a[mid] )
            if (a[mid] >= a[h]) {
                // a[h]~a[mid]为递增,a[mid+1]~a[t]为旋转数组
                result = x >= a[h] ? binarySearch(a, h, mid - 1, x) : search(a, mid + 1, t, x);
            } else {
                // a[h]~a[mid]为旋转数组,a[mid+1]~a[t]为递增
                result = x >= a[mid + 1] ? binarySearch(a, mid + 1, t, x) : search(a, h, mid - 1, x);
            }
        }
        return result;
    }

    // 第二种方法,先找出数组移位的位数,然后判断应该在哪一段进行二分查找
    private static int getMoveStep(int[] a, int h, int t) {
        if (h >= t) return 0;
        int low = h;
        int high = t;
        int mid = (low + high) / 2;
        int step = 0;
        if (a[low] == a[high]) {
            // 这是一种无法判断哪边是递增序列的情况
            step = getMoveStep(a, h, mid - 1);
            if (step == 0) step = getMoveStep(a, mid + 1, t);
        } else {
            while (a[low] > a[high]) {
                mid = (low + high) / 2;
                if (a[mid] >= a[low]) {
                    // 递增序列在mid左边
                    step = low = mid + 1;
                } else {
                    // 递增序列在mid右边
                    high = mid - 1;
                }
            }
        }
        return step;
    }
    
    // 利用y移位次数查找
    private static int searchByMove(int[] a, int x) {
        int result;
        int step = getMoveStep(a, 0, a.length - 1);
        if (step != 0) {
            result = x > a[0] ? binarySearch(a, 0, step - 1, x) : binarySearch(a, step, a.length - 1, x);
        } else {
            result = binarySearch(a, 0, a.length - 1, x);
        }
        return result;
    }

    private static int binarySearch(int[] a, int h, int t, int x) {
        int low = h;
        int high = t;
        int mid;
        while (low <= high) {
            mid = (low + high) / 2;
            if (a[mid] == x) {
                return mid;
            } else if (a[mid] < x) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] a = {4, 5, 1, 2, 3};
        int[] b = {5, 5, 5, 7, 5};
        int[] c = {5, 3, 5, 5, 5};
        int[] d = {5, 5, 3, 4, 5, 5, 5};
        int[] e = {5, 5, 5, 5, 5};
        int[] f = {1, 2, 3, 4, 5};
        System.out.println(search(a, 0, a.length - 1, 1));
        System.out.println(search(b, 0, b.length - 1, 7));
        System.out.println(search(c, 0, c.length - 1, 3));
        System.out.println(search(d, 0, d.length - 1, 3));
        System.out.println(search(e, 0, e.length - 1, 3));
        System.out.println(search(f, 0, f.length - 1, 2));
        System.out.println();
        System.out.println(searchByMove(a, 1));
        System.out.println(searchByMove(b, 7));
        System.out.println(searchByMove(c, 3));
        System.out.println(searchByMove(d, 3));
        System.out.println(searchByMove(e, 3));
        System.out.println(searchByMove(f, 2));
    }
}
posted on 2012-10-26 10:53  ZimZz  阅读(1417)  评论(0编辑  收藏  举报