#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;
void swap(int A[], int i, int j) {
if (i != j) {
int t = A[i];
A[i] = A[j];
A[j] =t;
}
}
int partition(int A[], int p, int r) {
int x = A[r];
int i = p - 1;
for (int j = p; j <= r-1; j++) {
if (A[j] <= x) {
i++;
swap(A, i, j);
}
}
swap(A, i+1, r);
return i+1;
}
int randomized_partition(int A[], int p, int r) {
srand(time(NULL));
int i = p + rand() % (r-p+1);
swap(A, i, r);
return partition(A, p, r);
}
int randomized_select(int A[], int p, int r, int i) {
if (p == r)
return A[p];
int q = randomized_partition(A, p, r);
int k = q - p + 1;
if (i == k)
return A[q];
else if (i < k)
return randomized_select(A, p, q-1, i);
else
return randomized_select(A, q+1, r, i-k);
}
void triplet_adjust(int A[], int i, int step) {
int j = i + step;
int k = i + 2 * step;
if (A[i] < A[j]) {
if (A[k] < A[i])
swap(A, i, j);
else if (A[k] < A[j])
swap(A, j, k);
}
else {
if (A[i] < A[k])
swap(A, i, j);
else if (A[k] > A[j])
swap(A, j, k);
}
}
double mean(int A[], int n) {
double f = A[0];
for (int i = 1; i < n; i++)
f += A[i];
return f / n;
}
int approximate_median(int A[], int r) {
int step = 1;
int size = 1;
int i;
for (int j = 0; j < r; j++)
size *= 3;
for (int k = 0; k < r; k++) {
i = (step - 1) / 2;
while (i < size) {
triplet_adjust(A, i, step);
i += (3 * step);
}
step *= 3;
}
return A[(size-1)/2];
}
void selection_sort(int A[], int left, int size, int step) {
int min;
int i, j;
for (i = left; i < left + (size-1) * step; i += step) {
min = i;
for (j = i+step; j < left + size; j += step) {
if (A[j] < A[min])
min = j;
}
swap(A, i, j);
}
}
const int SORT_NUM_THRESHOD = 50;
int approximate_median_any_n(int A[], int size) {
bool left_to_right = false;
int left = 0;
int step = 1;
int i;
while (size > SORT_NUM_THRESHOD) {
left_to_right = !left_to_right;
int rem = size % 3;
if (left_to_right)
i = left;
else
i = left + (3 + rem) * step;
for (int j = 0; j < (size / 3 - 1); j++) {
triplet_adjust(A, i, step);
i += 3 * step;
}
if (left_to_right)
left += step;
else {
i = left;
left += (1 + rem) * step;
}
selection_sort(A, i, 3 + rem, step);
if (rem == 2) {
if (left_to_right)
swap(A, i+step, i+2*step);
else
swap(A, i+2*step, i+3*step);
}
step *= 3;
size = size / 3;
}
selection_sort(A, left, size, step);
return A[left + step * int( (size-1) / 2 )];
}
int main(int argc, char* argv[])
{
const int DEFAULT_N = 1000000;
int N;
if (argc < 2) {
N = DEFAULT_N;
}
else {
N = atoi(argv[1]);
}
cout << "N = " << N << endl;
clock_t t = clock();
cout << clock() << endl;
int* A = new int[N];
cout << clock() << endl;
srand(time(NULL));
for (int i=0; i<N; i++) {
A[i] = rand() % N;
}
clock_t t1 = clock();
cout << t1 << endl;
double avg = mean(A, N);
cout << avg << endl;
clock_t t2 = clock();
cout << t2 << endl;
int m = approximate_median_any_n(A, N);
cout << m << endl;
clock_t t3 = clock();
cout << t3 << endl;
m = randomized_select(A, 0, N-1, N/2);
cout << m << endl;
clock_t t4 = clock();
cout << t4 << endl;
std::sort(A, A+N);
m = A[N/2];
cout << m << endl;
clock_t t5 = clock();
cout << t5 << endl;
cout << endl;
double dt = (double) (t2-t1) / CLOCKS_PER_SEC;
cout << dt << " " ;
dt = (double) (t3-t2) / CLOCKS_PER_SEC;
cout << dt << " " ;
dt = (double) (t4-t3) / CLOCKS_PER_SEC;
cout << dt << " " ;
dt = (double) (t5-t4) / CLOCKS_PER_SEC;
cout << dt << " " ;
cout << endl;
}