/*
*
* gengraph - generation of random simple connected graphs with prescribed
* degree sequence
*
* Copyright (C) 2006 Fabien Viger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef QSORT_H
#define QSORT_H
#include
#include
#ifndef register
#define register
#endif
namespace gengraph {
//___________________________________________________________________________
// check if every element is zero
inline bool check_zero(int *mem, int n) {
for (int *v = mem + n; v != mem; ) if (*(--v) != 0) {
return false;
}
return true;
}
//___________________________________________________________________________
// Sort simple integer arrays in ASCENDING order
//___________________________________________________________________________
inline int med3(int a, int b, int c) {
if (a < b) {
if (c < b) {
return (a < c) ? c : a;
} else {
return b;
}
} else {
if (c < a) {
return (b < c) ? c : b;
} else {
return a;
}
}
}
inline void isort(int *v, int t) {
if (t < 2) {
return;
}
for (int i = 1; i < t; i++) {
register int *w = v + i;
int tmp = *w;
while (w != v && *(w - 1) > tmp) {
*w = *(w - 1);
w--;
}
*w = tmp;
}
}
inline int partitionne(int *v, int t, int p) {
int i = 0;
int j = t - 1;
while (i < j) {
while (i <= j && v[i] < p) {
i++;
}
while (i <= j && v[j] > p) {
j--;
}
if (i < j) {
int tmp = v[i];
v[i++] = v[j];
v[j--] = tmp;
}
}
if (i == j && v[i] < p) {
i++;
}
assert(i != 0 && i != t);
return i;
}
inline void qsort(int *v, int t) {
if (t < 15) {
isort(v, t);
} else {
int x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2]));
qsort(v, x);
qsort(v + x, t - x);
}
}
inline int qsort_median(int *v, int t, int pos) {
if (t < 10) {
isort(v, t);
return v[pos];
}
int x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2]));
if (pos < x) {
return qsort_median(v, x, pos);
} else {
return qsort_median(v + x, t - x, pos - x);
}
}
inline int qsort_median(int *v, int t) {
return qsort_median(v, t, t / 2);
}
//___________________________________________________________________________
// Sort simple double arrays in ASCENDING order
//___________________________________________________________________________
inline double med3(double a, double b, double c) {
if (a < b) {
if (c < b) {
return (a < c) ? c : a;
} else {
return b;
}
} else {
if (c < a) {
return (b < c) ? c : b;
} else {
return a;
}
}
}
inline void isort(double *v, int t) {
if (t < 2) {
return;
}
for (int i = 1; i < t; i++) {
register double *w = v + i;
double tmp = *w;
while (w != v && *(w - 1) > tmp) {
*w = *(w - 1);
w--;
}
*w = tmp;
}
}
inline int partitionne(double *v, int t, double p) {
int i = 0;
int j = t - 1;
while (i < j) {
while (i <= j && v[i] < p) {
i++;
}
while (i <= j && v[j] > p) {
j--;
}
if (i < j) {
double tmp = v[i];
v[i++] = v[j];
v[j--] = tmp;
}
}
if (i == j && v[i] < p) {
i++;
}
assert(i != 0 && i != t);
return i;
}
inline void qsort(double *v, int t) {
if (t < 15) {
isort(v, t);
} else {
int x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2]));
qsort(v, x);
qsort(v + x, t - x);
}
}
inline double qsort_median(double *v, int t, int pos) {
if (t < 10) {
isort(v, t);
return v[pos];
}
int x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2]));
if (pos < x) {
return qsort_median(v, x, pos);
} else {
return qsort_median(v + x, t - x, pos - x);
}
}
inline double qsort_median(double *v, int t) {
return qsort_median(v, t, t / 2);
}
//___________________________________________________________________________
// Sort integer arrays according to value stored in mem[], in ASCENDING order
inline void isort(int *mem, int *v, int t) {
if (t < 2) {
return;
}
for (int i = 1; i < t; i++) {
int vtmp = v[i];
int tmp = mem[vtmp];
int j;
for (j = i; j > 0 && tmp < mem[v[j - 1]]; j--) {
v[j] = v[j - 1];
}
v[j] = vtmp;
}
}
inline void qsort(int *mem, int *v, int t) {
if (t < 15) {
isort(mem, v, t);
} else {
int p = med3(mem[v[t >> 1]], mem[v[(t >> 2) + 3]], mem[v[t - (t >> 1) - 3]]);
int i = 0;
int j = t - 1;
while (i < j) {
while (i <= j && mem[v[i]] < p) {
i++;
}
while (i <= j && mem[v[j]] > p) {
j--;
}
if (i < j) {
int tmp = v[i];
v[i++] = v[j];
v[j--] = tmp;
}
}
if (i == j && mem[v[i]] < p) {
i++;
}
assert(i != 0 && i != t);
qsort(mem, v, i);
qsort(mem, v + i, t - i);
}
}
//Box-Sort 1..n according to value stored in mem[], in DESCENDING order.
inline int *pre_boxsort(int *mem, int n, int &offset) {
int *yo;
// maximum and minimum
int mx = mem[0];
int mn = mem[0];
for (yo = mem + n - 1; yo != mem; yo--) {
register int x = *yo;
if (x > mx) {
mx = x;
}
if (x < mn) {
mn = x;
}
}
// box
int c = mx - mn + 1;
int *box = new int[c];
for (yo = box + c; yo != box; * (--yo) = 0) { }
for (yo = mem + n; yo != mem; box[*(--yo) - mn]++) { }
// cumul sum
int sum = 0;
for (yo = box + c; yo != box; ) {
sum += *(--yo);
*yo = sum;
}
offset = mn;
return box;
}
inline int *boxsort(int *mem, int n, int *buff = NULL) {
int i;
if (n <= 0) {
return buff;
}
int offset = 0;
int *box = pre_boxsort(mem, n, offset);
// sort
if (buff == NULL) {
buff = new int[n];
}
for (i = 0; i < n; i++) {
buff[--box[mem[i] - offset]] = i;
}
// clean
delete[] box;
return buff;
}
// merge two sorted arays in their intersection. Store the result in first array, and return length
inline int intersect(int *a, int a_len, int *b, int b_len) {
if (a_len == 0 || b_len == 0) {
return 0;
}
int *asup = a + a_len;
int *bsup = b + b_len;
int len = 0;
int *p = a;
do {
if (*a == *b) {
p[len++] = *a;
}
do if (++a == asup) {
return len;
} while (*a < *b);
if (*a == *b) {
p[len++] = *a;
}
do if (++b == bsup) {
return len;
} while (*b < *a);
} while (true);
}
// merge two sorted arays in their union, store result in m
inline int unify(int *m, int *a, int a_len, int *b, int b_len) {
int *asup = a + a_len;
int *bsup = b + b_len;
int len = 0;
while (a != asup && b != bsup) {
if (*a < *b) {
m[len++] = *(a++);
} else {
if (*a == *b) {
a++;
}
m[len++] = *(b++);
}
}
while (a != asup) {
m[len++] = *(a++);
}
while (b != asup) {
m[len++] = *(b++);
}
return len;
}
// lexicographic compare
inline int lex_comp(int *v1, int *v2, int n) {
int *stop = v1 + n;
while (v1 != stop && *v1 == *v2) {
v1++;
v2++;
};
if (v1 == stop) {
return 0;
} else if (*v1 < *v2) {
return -1;
} else {
return 1;
}
}
// lexicographic median of three
inline int *lex_med3(int *a, int *b, int *c, int s) {
int ab = lex_comp(a, b, s);
if (ab == 0) {
return a;
} else {
int cb = lex_comp(c, b, s);
if (cb == 0) {
return b;
}
int ca = lex_comp(c, a, s);
if (ab < 0) {
if (cb > 0) {
return b;
} else {
return (ca > 0) ? c : a;
}
} else {
if (cb < 0) {
return b;
} else {
return (ca < 0) ? c : a;
}
}
}
}
// Lexicographic sort
inline void lex_isort(int **l, int *v, int t, int s) {
if (t < 2) {
return;
}
for (int i = 1; i < t; i++) {
register int *w = v + i;
int tmp = *w;
while (w != v && lex_comp(l[tmp], l[*(w - 1)], s) < 0) {
*w = *(w - 1);
w--;
}
*w = tmp;
}
}
#ifdef _STABLE_SORT_ONLY
#define _CRITICAL_SIZE_QSORT 0x7FFFFFFF
#warning "lex_qsort will be replaced by lex_isort"
#else
#define _CRITICAL_SIZE_QSORT 15
#endif
inline void lex_qsort(int **l, int *v, int t, int s) {
if (t < _CRITICAL_SIZE_QSORT) {
lex_isort(l, v, t, s);
} else {
int *p = lex_med3(l[v[t >> 1]], l[v[(t >> 2) + 2]], l[v[t - (t >> 1) - 2]], s);
int i = 0;
int j = t - 1;
// printf("pivot = %d\n",p);
while (i < j) {
// for(int k=0; k 0) {
j--;
}
if (i < j) {
// printf(" swap %d[%d] with %d[%d]\n",i,v[i],j,v[j]);
int tmp = v[i];
v[i++] = v[j];
v[j--] = tmp;
}
}
if (i == j && lex_comp(l[v[i]], p, s) < 0) {
i++;
}
assert(i != 0 && i != t);
lex_qsort(l, v, i, s);
lex_qsort(l, v + i, t - i, s);
}
}
// lexicographic indirect compare
inline int lex_comp_indirect(int *key, int *v1, int *v2, int n) {
int *stop = v1 + n;
while (v1 != stop && key[*v1] == key[*v2]) {
v1++;
v2++;
};
if (v1 == stop) {
return 0;
} else if (key[*v1] < key[*v2]) {
return -1;
} else {
return 1;
}
}
inline int qsort_min(const int a, const int b) {
return a <= b ? a : b;
}
// mix indirect compare
inline int mix_comp_indirect(int *key, int a, int b, int **neigh, int *degs) {
if (key[a] < key[b]) {
return -1;
} else if (key[a] > key[b]) {
return 1;
} else {
int cmp = lex_comp_indirect(key, neigh[a], neigh[b], qsort_min(degs[a], degs[b]));
if (cmp == 0) {
if (degs[a] > degs[b]) {
return -1;
}
if (degs[a] < degs[b]) {
return 1;
}
}
return cmp;
}
}
// lexicographic indirect median of three
inline int mix_med3_indirect(int *key, int a, int b, int c, int **neigh, int *degs) {
int ab = mix_comp_indirect(key, a, b, neigh, degs);
if (ab == 0) {
return a;
} else {
int cb = mix_comp_indirect(key, c, b, neigh, degs);
if (cb == 0) {
return b;
}
int ca = mix_comp_indirect(key, c, a, neigh, degs);
if (ab < 0) {
if (cb > 0) {
return b;
} else {
return (ca > 0) ? c : a;
}
} else {
if (cb < 0) {
return b;
} else {
return (ca < 0) ? c : a;
}
}
}
}
// Sort integer arrays in ASCENDING order
inline void mix_isort_indirect(int *key, int *v, int t, int **neigh, int *degs) {
if (t < 2) {
return;
}
for (int i = 1; i < t; i++) {
register int *w = v + i;
int tmp = *w;
while (w != v && mix_comp_indirect(key, tmp, *(w - 1), neigh, degs) < 0) {
*w = *(w - 1);
w--;
}
*w = tmp;
}
}
inline void mix_qsort_indirect(int *key, int *v, int t, int **neigh, int *degs) {
if (t < 15) {
mix_isort_indirect(key, v, t, neigh, degs);
} else {
int p = mix_med3_indirect(key, v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2], neigh, degs);
int i = 0;
int j = t - 1;
// printf("pivot = %d\n",p);
while (i < j) {
// for(int k=0; k 0) {
j--;
}
if (i < j) {
// printf(" swap %d[%d] with %d[%d]\n",i,v[i],j,v[j]);
int tmp = v[i];
v[i++] = v[j];
v[j--] = tmp;
}
}
if (i == j && mix_comp_indirect(key, v[i], p, neigh, degs) < 0) {
i++;
}
assert(i != 0 && i != t);
mix_qsort_indirect(key, v, i, neigh, degs);
mix_qsort_indirect(key, v + i, t - i, neigh, degs);
}
}
} // namespace gengraph
#endif //QSORT_H