307 lines
6.6 KiB
Java
307 lines
6.6 KiB
Java
import java.util.*;
|
|
import java.util.function.IntPredicate;
|
|
|
|
public class Sort {
|
|
|
|
static Random rnd = new Random(1);
|
|
|
|
public static void qSort(int[] a, int low, int high) {
|
|
if (low >= high)
|
|
return;
|
|
int separator = a[low + rnd.nextInt(high - low + 1)];
|
|
int i = low;
|
|
int j = high;
|
|
do {
|
|
while (a[i] < separator)
|
|
++i;
|
|
while (a[j] > separator)
|
|
--j;
|
|
if (i > j)
|
|
break;
|
|
int t = a[i];
|
|
a[i] = a[j];
|
|
a[j] = t;
|
|
++i;
|
|
--j;
|
|
} while (i <= j);
|
|
qSort(a, low, j);
|
|
qSort(a, i, high);
|
|
}
|
|
|
|
public static void mergeSort(int[] a, int low, int high) {
|
|
if (high - low < 2)
|
|
return;
|
|
int mid = (low + high) >>> 1;
|
|
mergeSort(a, low, mid);
|
|
mergeSort(a, mid, high);
|
|
int[] b = Arrays.copyOfRange(a, low, mid);
|
|
for (int i = low, j = mid, k = 0; k < b.length; i++) {
|
|
if (j == high || b[k] <= a[j]) {
|
|
a[i] = b[k++];
|
|
} else {
|
|
a[i] = a[j++];
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void mergeSort2(int[] a, int low, int high) {
|
|
int size = high - low;
|
|
if (size < 2)
|
|
return;
|
|
int mid = (low + high) >>> 1;
|
|
mergeSort2(a, low, mid);
|
|
mergeSort2(a, mid, high);
|
|
int[] b = new int[size];
|
|
int i = low;
|
|
int j = mid;
|
|
for (int k = 0; k < size; k++) {
|
|
if (i < mid && (j == high || a[i] <= a[j])) {
|
|
b[k] = a[i++];
|
|
} else {
|
|
b[k] = a[j++];
|
|
}
|
|
}
|
|
System.arraycopy(b, 0, a, low, size);
|
|
}
|
|
|
|
public static void inPlaceMergeSort(int[] a, int low, int high) {
|
|
if (low < high - 1) {
|
|
int mid = (low + high) >>> 1;
|
|
mergeSort(a, low, mid);
|
|
mergeSort(a, mid, high);
|
|
inPlaceMerge(a, low, mid, high);
|
|
}
|
|
}
|
|
|
|
// O(n*log(n)) complexity
|
|
static void inPlaceMerge(int[] a, int from, int mid, int to) {
|
|
if (from >= mid || mid >= to) return;
|
|
if (to - from == 2) {
|
|
if (a[from] > a[mid])
|
|
swap(a, from, mid);
|
|
return;
|
|
}
|
|
|
|
final int firstCut;
|
|
final int secondCut;
|
|
|
|
if (mid - from > to - mid) {
|
|
firstCut = from + (mid - from) / 2;
|
|
secondCut = binarySearchFirstTrue(i -> a[i] >= a[firstCut], mid, to);
|
|
} else {
|
|
secondCut = mid + (to - mid) / 2;
|
|
firstCut = binarySearchFirstTrue(i -> a[i] > a[secondCut], from, mid);
|
|
}
|
|
|
|
if (mid != firstCut && mid != secondCut) {
|
|
rotate(a, firstCut, mid, secondCut);
|
|
}
|
|
|
|
mid = firstCut + (secondCut - mid);
|
|
inPlaceMerge(a, from, firstCut, mid);
|
|
inPlaceMerge(a, mid, secondCut, to);
|
|
}
|
|
|
|
static void swap(int[] a, int i, int j) {
|
|
int t = a[j];
|
|
a[j] = a[i];
|
|
a[i] = t;
|
|
}
|
|
|
|
static void rotate(int[] a, int first, int middle, int last) {
|
|
int next = middle;
|
|
while (first != next) {
|
|
swap(a, first++, next++);
|
|
if (next == last)
|
|
next = middle;
|
|
else if (first == middle)
|
|
middle = next;
|
|
}
|
|
}
|
|
|
|
static int binarySearchFirstTrue(IntPredicate predicate, int fromInclusive, int toExclusive) {
|
|
int lo = fromInclusive - 1;
|
|
int hi = toExclusive;
|
|
while (lo < hi - 1) {
|
|
int mid = (lo + hi) >>> 1;
|
|
if (!predicate.test(mid)) {
|
|
lo = mid;
|
|
} else {
|
|
hi = mid;
|
|
}
|
|
}
|
|
return hi;
|
|
}
|
|
|
|
public static void heapSort(int[] a) {
|
|
int n = a.length;
|
|
for (int i = n / 2 - 1; i >= 0; i--)
|
|
pushDown(a, i, n);
|
|
while (n > 1) {
|
|
swap(a, 0, n - 1);
|
|
pushDown(a, 0, --n);
|
|
}
|
|
}
|
|
|
|
static void pushDown(int[] h, int pos, int size) {
|
|
while (true) {
|
|
int child = 2 * pos + 1;
|
|
if (child >= size)
|
|
break;
|
|
if (child + 1 < size && h[child + 1] > h[child])
|
|
child++;
|
|
if (h[pos] >= h[child])
|
|
break;
|
|
swap(h, pos, child);
|
|
pos = child;
|
|
}
|
|
}
|
|
|
|
public static void bubbleSort(int[] a) {
|
|
for (int i = 0; i + 1 < a.length; i++) {
|
|
for (int j = 0; j + 1 < a.length; j++) {
|
|
if (a[j] > a[j + 1]) {
|
|
swap(a, j, j + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void selectionSort(int[] a) {
|
|
int n = a.length;
|
|
int[] p = new int[n];
|
|
for (int i = 0; i < n; i++)
|
|
p[i] = i;
|
|
for (int i = 0; i < n - 1; i++) {
|
|
for (int j = i + 1; j < n; j++) {
|
|
if (a[p[i]] > a[p[j]]) {
|
|
swap(p, i, j);
|
|
}
|
|
}
|
|
}
|
|
int[] b = a.clone();
|
|
for (int i = 0; i < n; i++)
|
|
a[i] = b[p[i]];
|
|
}
|
|
|
|
public static void insertionSort(int[] a) {
|
|
for (int i = 1; i < a.length; i++) {
|
|
for (int j = i; j > 0; j--) {
|
|
if (a[j - 1] > a[j]) {
|
|
swap(a, j - 1, j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void countingSort(int[] a) {
|
|
int max = 0;
|
|
for (int x : a) {
|
|
max = Math.max(max, x);
|
|
}
|
|
int[] cnt = new int[max + 1];
|
|
for (int x : a) {
|
|
++cnt[x];
|
|
}
|
|
for (int i = 1; i < cnt.length; i++) {
|
|
cnt[i] += cnt[i - 1];
|
|
}
|
|
int n = a.length;
|
|
int[] b = new int[n];
|
|
for (int i = 0; i < n; i++) {
|
|
b[--cnt[a[i]]] = a[i];
|
|
}
|
|
System.arraycopy(b, 0, a, 0, n);
|
|
}
|
|
|
|
public static void radixSort(int[] a) {
|
|
final int d = 8;
|
|
final int w = 32;
|
|
int[] t = new int[a.length];
|
|
for (int p = 0; p < w / d; p++) {
|
|
// counting-sort
|
|
int[] cnt = new int[1 << d];
|
|
for (int i = 0; i < a.length; i++)
|
|
++cnt[((a[i] ^ Integer.MIN_VALUE) >>> (d * p)) & ((1 << d) - 1)];
|
|
for (int i = 1; i < cnt.length; i++)
|
|
cnt[i] += cnt[i - 1];
|
|
for (int i = a.length - 1; i >= 0; i--)
|
|
t[--cnt[((a[i] ^ Integer.MIN_VALUE) >>> (d * p)) & ((1 << d) - 1)]] = a[i];
|
|
System.arraycopy(t, 0, a, 0, a.length);
|
|
}
|
|
}
|
|
|
|
// random test
|
|
public static void main(String[] args) {
|
|
Random rnd = new Random(1);
|
|
for (int step = 0; step < 1000; step++) {
|
|
int n = rnd.nextInt(10) + 1;
|
|
int[] a = rnd.ints(n, 0, 1000).toArray();
|
|
int[] s = a.clone();
|
|
Arrays.sort(s);
|
|
|
|
int[] b = a.clone();
|
|
bubbleSort(b);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
selectionSort(b);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
insertionSort(b);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
countingSort(b);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
qSort(b, 0, b.length - 1);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
}
|
|
|
|
for (int step = 0; step < 10; step++) {
|
|
int n = rnd.nextInt(50_000) + 100_000;
|
|
int[] a = step == 0 ? new int[n] : rnd.ints(n).toArray();
|
|
int[] s = a.clone();
|
|
Arrays.sort(s);
|
|
|
|
int[] b = a.clone();
|
|
qSort(b, 0, b.length - 1);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
mergeSort(b, 0, b.length);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
mergeSort2(b, 0, b.length);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
inPlaceMergeSort(b, 0, b.length);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
heapSort(b);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
|
|
b = a.clone();
|
|
radixSort(b);
|
|
if (!Arrays.equals(s, b))
|
|
throw new RuntimeException();
|
|
}
|
|
}
|
|
}
|