After sorting, invert the second half of the array:
now the rest of the problem is to do a perfect shuffle of the array elements - a problem to come up time and again.
If you want to apply a permutation in-place and know how to transform indices, you can keep a "scoreboard" of indices handled - but even a single bit per item is O(n) storage. (Find the next index still needing handling and perform the cycle containing it, keeping scores, until all indices are handled.)
A pretty nice rendition of an in-place perfect shuffle in linear time and constant space in addition to the array is Aryabhata's over at CS. The method has been placed at arxiv.org by Peiyush Jain.
(The complexity of the sort as a first step may dominate the permutation/shuffle step(s).)
There is another interpretation of this task, or the sort step: sort into a folded array.
The sort lending itself most readily to this task got to be the double-ended selection sort:
In each pass over the data not yet placed, determine the min and max in 3/2n comparisons and swap into their positions, until one value or none at all is left.
Or take a standard sort method, and have the indexes mapped. For the hell of it:
/** Anything with accessors with int parameter */
interface Indexable<T> {
T get(int index);
T set(int index, T value);
// int size(); // YAGNI?
}
/** The accessors have this folded in half,
* while iterator() is not overridden */
@SuppressWarnings("serial")
class FoldedList<T> extends ArrayList<T>
implements Indexable<T> {
public FoldedList(@SuppressWarnings("unchecked") T...elements) {
super(Arrays.asList(elements));
}
int map(int index) {
final int last = size()-1;
index = 2*index;
return last <= index ? 2*last-index : index+1;
}
@Override
public T get(int index) { return super.get(map(index)); }
@Override
public T set(int index, T element) {
return super.set(map(index), element);
}
}
/** Sort an Indexable<T> */
public class Sort {
// Hoare/Sedgewick using middle index for pivot
private static <T extends Comparable<T>>
int split(Indexable<T> ixable, int lo, int hi) {
int
mid = lo + (hi-lo)/2,
left = lo+1,
right= hi-1;
T pivot = ixable.get(mid),
l = null, r = null;
ixable.set(mid, ixable.get(lo));
scan:
while (true) {
while ((l = ixable.get(left)).compareTo(pivot) < 0)
if (right < ++left) {
left--;
break scan;
}
while (pivot.compareTo(r = ixable.get(right)) < 0)
if (--right <= left) {
left -= 1;
l = ixable.get(left);
break scan;
}
ixable.set(left, r); // place misplaced items
ixable.set(right, l);
if (--right < ++left) {
left = right;
l = r;
break;
}
}
ixable.set(lo, l); // put last left value into first position
ixable.set(left, pivot); // place pivot at split index
return left;
}
private static <T extends Comparable<T>>
void sort(Indexable<T> ixable, int lo, int hi) {
while (lo+2 < hi) { // more than 2 Ts
int split = split(ixable, lo, hi);
if (split - lo < hi - split) {
sort(ixable, lo, split); // left part smaller
lo = split + 1;
} else {
sort(ixable, split+1, hi); // right part smaller
hi = split;
}
}
T l, h;
if (lo < --hi // 2 Ts
&& (l = ixable.get(lo)).compareTo(h = ixable.get(hi)) > 0) {
ixable.set(lo, h); // exchange
ixable.set(hi, l);
}
}
public static <T extends Comparable<T>>
void main(String[] args) {
Indexable<Number> nums = new FoldedList<>( //2,6,1,7,9,3);
7, 3, 9, 3, 0, 6, 1, 2, 8, 6, 5, 4, 7);
sort((Indexable<T>) nums);
System.out.println(nums);
}
}