package class20; import java.util.Arrays; public class Code03_ShuffleProblem { // 数组的长度为len,调整前的位置是i,返回调整之后的位置 // 下标不从0开始,从1开始 public static int modifyIndex1(int i, int len) { if (i <= len / 2) { return 2 * i; } else { return 2 * (i - (len / 2)) - 1; } } // 数组的长度为len,调整前的位置是i,返回调整之后的位置 // 下标不从0开始,从1开始 public static int modifyIndex2(int i, int len) { return (2 * i) % (len + 1); } // 主函数 // 数组必须不为空,且长度为偶数 public static void shuffle(int[] arr) { if (arr != null && arr.length != 0 && (arr.length & 1) == 0) { shuffle(arr, 0, arr.length - 1); } } // 在arr[L..R]上做完美洗牌的调整(arr[L..R]范围上一定要是偶数个数字) public static void shuffle(int[] arr, int L, int R) { while (R - L + 1 > 0) { // 切成一块一块的解决,每一块的长度满足(3^k)-1 int len = R - L + 1; int base = 3; int k = 1; // 计算小于等于len并且是离len最近的,满足(3^k)-1的数 // 也就是找到最大的k,满足3^k <= len+1 while (base <= (len + 1) / 3) { // base > (N+1)/3 base *= 3; k++; } // 3^k -1 // 当前要解决长度为base-1的块,一半就是再除2 int half = (base - 1) / 2; // [L..R]的中点位置 int mid = (L + R) / 2; // 要旋转的左部分为[L+half...mid], 右部分为arr[mid+1..mid+half] // 注意在这里,arr下标是从0开始的 rotate(arr, L + half, mid, mid + half); // 旋转完成后,从L开始算起,长度为base-1的部分进行下标连续推 cycles(arr, L, base - 1, k); // 解决了前base-1的部分,剩下的部分继续处理 L = L + base - 1; // L -> [] [+1...R] } } // 从start位置开始,往右len的长度这一段,做下标连续推 // 出发位置依次为1,3,9... public static void cycles(int[] arr, int start, int len, int k) { // 找到每一个出发位置trigger,一共k个 // 每一个trigger都进行下标连续推 // 出发位置是从1开始算的,而数组下标是从0开始算的。 for (int i = 0, trigger = 1; i < k; i++, trigger *= 3) { int preValue = arr[trigger + start - 1]; int cur = modifyIndex2(trigger, len); while (cur != trigger) { int tmp = arr[cur + start - 1]; arr[cur + start - 1] = preValue; preValue = tmp; cur = modifyIndex2(cur, len); } arr[cur + start - 1] = preValue; } } // [L..M]为左部分,[M+1..R]为右部分,左右两部分互换 public static void rotate(int[] arr, int L, int M, int R) { reverse(arr, L, M); reverse(arr, M + 1, R); reverse(arr, L, R); } // [L..R]做逆序调整 public static void reverse(int[] arr, int L, int R) { while (L < R) { int tmp = arr[L]; arr[L++] = arr[R]; arr[R--] = tmp; } } public static void wiggleSort(int[] arr) { if (arr == null || arr.length == 0) { return; } // 假设这个排序是额外空间复杂度O(1)的,当然系统提供的排序并不是,你可以自己实现一个堆排序 Arrays.sort(arr); if ((arr.length & 1) == 1) { shuffle(arr, 1, arr.length - 1); } else { shuffle(arr, 0, arr.length - 1); for (int i = 0; i < arr.length; i += 2) { int tmp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = tmp; } } } // for test public static boolean isValidWiggle(int[] arr) { for (int i = 1; i < arr.length; i++) { if ((i & 1) == 1 && arr[i] < arr[i - 1]) { return false; } if ((i & 1) == 0 && arr[i] > arr[i - 1]) { return false; } } return true; } // for test public static void printArray(int[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } // for test public static int[] generateArray() { int len = (int) (Math.random() * 10) * 2; int[] arr = new int[len]; for (int i = 0; i < len; i++) { arr[i] = (int) (Math.random() * 100); } return arr; } public static void main(String[] args) { for (int i = 0; i < 5000000; i++) { int[] arr = generateArray(); wiggleSort(arr); if (!isValidWiggle(arr)) { System.out.println("ooops!"); printArray(arr); break; } } } }