Retro68/gcc/libphobos/libdruntime/rt/util/container/treap.d
Wolfgang Thaller 6fbf4226da gcc-9.1
2019-06-20 20:10:10 +02:00

339 lines
7.3 KiB
D

/**
* Treap container for internal usage.
*
* Copyright: Copyright Digital Mars 2014 - 2014.
* License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
*/
module rt.util.container.treap;
static import common = rt.util.container.common;
import rt.util.random;
import rt.qsort;
struct Treap(E)
{
nothrow:
static struct Node
{
Node* left, right;
E element;
uint priority;
}
@disable this(this);
~this()
{
removeAll();
}
void initialize()
{
rand48.defaultSeed();
}
void insert(E element) @nogc
{
root = insert(root, element);
}
void remove(E element)
{
remove(&root, element);
}
int opApply(scope int delegate(ref E) nothrow dg)
{
return (cast(const)&this).opApply((ref const E e) => dg(*cast(E*)&e));
}
int opApply(scope int delegate(ref const E) nothrow dg) const
{
return opApplyHelper(root, dg);
}
version (unittest)
bool opEquals(E[] elements)
{
size_t i;
foreach (e; this)
{
if (i >= elements.length)
return false;
if (e != elements[i++])
return false;
}
return i == elements.length;
}
void removeAll()
{
removeAll(root);
root = null;
}
version (unittest)
bool valid()
{
return valid(root);
}
version (none)
uint height()
{
static uint height(Node* node)
{
if (!node)
return 0;
auto left = height(node.left);
auto right = height(node.right);
return 1 + (left > right ? left : right);
}
return height(root);
}
version (none)
size_t count()
{
static size_t count(Node* node)
{
if (!node)
return 0;
return count(node.left) + count(node.right) + 1;
}
return count(root);
}
private:
Node* root;
Rand48 rand48;
Node* allocNode(E element) @nogc
{
Node* node = cast(Node*)common.xmalloc(Node.sizeof);
node.left = node.right = null;
node.priority = rand48();
node.element = element;
return node;
}
Node* insert(Node* node, E element) @nogc
{
if (!node)
return allocNode(element);
else if (element < node.element)
{
node.left = insert(node.left, element);
if (node.left.priority < node.priority)
node = rotateR(node);
}
else if (element > node.element)
{
node.right = insert(node.right, element);
if (node.right.priority < node.priority)
node = rotateL(node);
}
else
{} // ignore duplicate
return node;
}
static:
void freeNode(Node* node)
{
common.free(node);
}
Node* rotateL(Node* root)
{
auto pivot = root.right;
root.right = pivot.left;
pivot.left = root;
return pivot;
}
Node* rotateR(Node* root)
{
auto pivot = root.left;
root.left = pivot.right;
pivot.right = root;
return pivot;
}
void remove(Node** ppnode, E element)
{
Node* node = *ppnode;
if (!node)
return; // element not in treap
if (element < node.element)
{
remove(&node.left, element);
}
else if (element > node.element)
{
remove(&node.right, element);
}
else
{
while (node.left && node.right)
{
if (node.left.priority < node.right.priority)
{
*ppnode = rotateR(node);
ppnode = &(*ppnode).right;
}
else
{
*ppnode = rotateL(node);
ppnode = &(*ppnode).left;
}
}
if (!node.left)
*ppnode = node.right;
else
*ppnode = node.left;
freeNode(node);
}
}
void removeAll(Node* node)
{
if (!node)
return;
removeAll(node.left);
removeAll(node.right);
freeNode(node);
}
int opApplyHelper(const Node* node, scope int delegate(ref const E) nothrow dg)
{
if (!node)
return 0;
int result = opApplyHelper(node.left, dg);
if (result)
return result;
result = dg(node.element);
if (result)
return result;
return opApplyHelper(node.right, dg);
}
version (unittest)
bool valid(Node* node)
{
if (!node)
return true;
if (node.left)
{
if (node.left.priority < node.priority)
return false;
if (node.left.element > node.element)
return false;
}
if (node.right)
{
if (node.right.priority < node.priority)
return false;
if (node.right.element < node.element)
return false;
}
return valid(node.left) && valid(node.right);
}
}
unittest
{
// randomized unittest for randomized data structure
import /*cstdlib = */core.stdc.stdlib : rand, srand;
import /*ctime = */core.stdc.time : time;
enum OP { add, remove }
enum initialSize = 1000;
enum randOps = 1000;
Treap!uint treap;
OP[] ops;
uint[] opdata;
treap.initialize();
srand(cast(uint)time(null));
uint[] data;
initialLoop:
foreach (i; 0 .. initialSize)
{
data ~= rand();
treap.insert(data[$-1]);
foreach (e; data[0..$-1])
if (e == data[$-1])
{
data = data[0..$-1];
continue initialLoop;
}
}
_adSort(*cast(void[]*)&data, typeid(data[0]));
assert(treap == data);
assert(treap.valid());
for (int i = randOps; i > 0; --i)
{
ops ~= cast(OP)(rand() < uint.max / 2 ? OP.add: OP.remove);
opdata ~= rand();
}
foreach (op; ops)
{
if (op == OP.add)
{
treap.insert(opdata[0]);
size_t i;
for (i = 0; i < data.length; ++i)
if (data[i] >= opdata[0])
break;
if (i == data.length || data[i] != opdata[0])
{ // not a duplicate
data.length++;
uint tmp = opdata[0];
for (; i < data.length; ++i)
{
uint tmp2 = data[i];
data[i] = tmp;
tmp = tmp2;
}
}
}
else if (!data.length) // nothing to remove
{
opdata = opdata[1..$];
continue;
}
else
{
uint tmp = data[opdata[0]%data.length];
treap.remove(tmp);
size_t i;
for (i = 0; data[i] < tmp; ++i)
{}
for (; i < data.length-1; ++i)
data[i] = data[i+1];
data.length--;
}
assert(treap.valid());
assert(treap == data);
opdata = opdata[1..$];
}
treap.removeAll();
data.length = 0;
assert(treap == data);
}