<tb@panthema.net>
<http://www.gnu.org/licenses/>
namespace bingmann_sample_sortBT {
using namespace bingmann_sample_sort;
inline unsigned int
find_bkt_tree(const key_type& key, const key_type* splitter, const key_type* splitter_tree0, size_t numsplitters)
{
#if 1
const key_type* splitter_tree = splitter_tree0 - 1;
unsigned int i = 1;
while ( i < numsplitters+1 )
{
if (key <= splitter_tree[i])
i = 2*i + 0;
else
i = 2*i + 1;
}
i -= numsplitters+1;
size_t b = i * 2;
if (i < numsplitters && splitter[i] == key) b += 1;
#else
const key_type* splitter_tree = splitter_tree0 - 1;
unsigned int i = 1;
unsigned int ll = 1;
while ( i <= numsplitters )
{
if (key <= splitter_tree[i]) {
ll = i;
i = 2*i + 0;
}
else
i = 2*i + 1;
}
i -= numsplitters+1;
#if 0
int pos = numsplitters-1;
while ( pos >= 0 && key <= splitter[pos] ) --pos;
pos++;
std::cout << "i " << i << " pos " << pos << "\n";
assert(i == pos);
#endif
assert(i >= numsplitters || splitter_tree[ll] == splitter[i]);
size_t b = i * 2;
if (i < numsplitters && splitter_tree[ll] == key) b += 1;
#endif
return b;
}
void sample_sortBT(string* strings, size_t n, size_t depth)
{
#if 0
static const size_t numsplitters = 31;
#else
static const size_t numsplitters2 = ( l2cache - sizeof(size_t) ) / (sizeof(key_type) + 2 * sizeof(size_t));
static const size_t numsplitters = (1 << logfloor_<numsplitters2>::value) - 1;
#endif
if (n < g_samplesort_smallsort)
{
g_rs_steps++;
return bingmann_radix_sort::msd_CI5(strings, n, depth);
}
g_ss_steps++;
size_t samplesize = oversample_factor * numsplitters;
key_type* samples = new key_type[ samplesize ];
LCGRandom rng(&samples);
for (unsigned int i = 0; i < samplesize; ++i)
{
samples[i] = get_char<key_type>(strings[ rng() % n ], depth);
}
std::sort(samples, samples + samplesize);
key_type splitter[numsplitters];
unsigned char splitter_lcp[numsplitters];
DBG(debug_splitter, "splitter:");
splitter_lcp[0] = 0;
for (size_t i = 0, j = oversample_factor/2; i < numsplitters; ++i)
{
splitter[i] = samples[j];
DBG(debug_splitter, "key " << toHex(splitter[i]));
if (i != 0) {
key_type xorSplit = splitter[i-1] ^ splitter[i];
DBG1(debug_splitter, " XOR -> " << toHex(xorSplit) << " - ");
DBG3(debug_splitter, count_high_zero_bits(xorSplit) << " bits = "
<< count_high_zero_bits(xorSplit) / 8 << " chars lcp");
splitter_lcp[i] = count_high_zero_bits(xorSplit) / 8;
}
j += oversample_factor;
}
delete [] samples;
key_type splitter_tree[numsplitters];
{
size_t t = 0;
size_t highbit = (numsplitters+1) / 2;
while ( highbit > 0 )
{
DBG(debug_splitter_tree, "highbit = " << highbit);
size_t p = highbit-1;
size_t inc = highbit << 1;
while ( p <= numsplitters )
{
DBG(debug_splitter_tree, "p = " << p);
splitter_tree[t++] = splitter[p];
p += inc;
}
highbit >>= 1;
}
}
if (debug_splitter_tree)
{
DBG1(1, "splitter_tree: ");
for (size_t i = 0; i < numsplitters; ++i)
{
DBG2(1, splitter_tree[i] << " ");
}
DBG3(1, "");
}
static const size_t bktnum = 2*numsplitters+1;
size_t* bktsize = new size_t[bktnum];
memset(bktsize, 0, bktnum * sizeof(size_t));
for (size_t si = 0; si < n; ++si)
{
key_type key = get_char<key_type>(strings[si], depth);
unsigned int b = find_bkt_tree(key, splitter, splitter_tree, numsplitters);
assert(b < bktnum);
++bktsize[ b ];
}
if (debug_bucketsize)
{
DBG1(1, "bktsize: ");
for (size_t i = 0; i < bktnum; ++i)
{
DBG2(1, bktsize[i] << " ");
}
DBG3(1, "");
}
size_t bktindex[bktnum];
bktindex[0] = bktsize[0];
size_t last_bkt_size = bktsize[0];
for (unsigned int i=1; i < bktnum; ++i) {
bktindex[i] = bktindex[i-1] + bktsize[i];
if (bktsize[i]) last_bkt_size = bktsize[i];
}
assert(bktindex[bktnum-1] == n);
for (size_t i=0, j; i < n - last_bkt_size; )
{
string perm = strings[i];
key_type key;
unsigned int b;
while (1)
{
key = get_char<key_type>(perm, depth);
b = find_bkt_tree(key, splitter, splitter_tree, numsplitters);
j = --bktindex[ b ];
if ( j <= i )
break;
std::swap(perm, strings[j]);
}
strings[i] = perm;
i += bktsize[ b ];
}
size_t i = 0, bsum = 0;
while (i < bktnum-1)
{
if (bktsize[i] > 1)
{
DBG(debug_recursion, "Recurse[" << depth << "]: < bkt " << bsum << " size " << bktsize[i] << " lcp " << int(splitter_lcp[i/2]));
sample_sortBT(strings+bsum, bktsize[i], depth + splitter_lcp[i/2]);
}
bsum += bktsize[i++];
if (bktsize[i] > 1)
{
if ( (splitter[i/2] & 0xFF) == 0 ) {
DBG(debug_recursion, "Recurse[" << depth << "]: = bkt " << bsum << " size " << bktsize[i] << " is done!");
}
else {
DBG(debug_recursion, "Recurse[" << depth << "]: = bkt " << bsum << " size " << bktsize[i] << " lcp keydepth!");
sample_sortBT(strings+bsum, bktsize[i], depth + sizeof(key_type));
}
}
bsum += bktsize[i++];
}
if (bktsize[i] > 0)
{
DBG(debug_recursion, "Recurse[" << depth << "]: > bkt " << bsum << " size " << bktsize[i] << " no lcp");
sample_sortBT(strings+bsum, bktsize[i], depth);
}
bsum += bktsize[i++];
assert(i == bktnum && bsum == n);
delete [] bktsize;
}
void bingmann_sample_sortBT(string* strings, size_t n)
{
sample_sort_pre();
sample_sortBT(strings,n,0);
sample_sort_post();
}
CONTESTANT_REGISTER(bingmann_sample_sortBT, "bingmann/sample_sortBT",
"bingmann/sample_sortBT (binary tree, no cache)")
}