added new item tower height generator for skiplist
This commit is contained in:
parent
7c0e34aac9
commit
adc80bf29a
24
data_structures/skiplist/new_height.hpp
Normal file
24
data_structures/skiplist/new_height.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef MEMGRAPH_DATA_STRUCTURES_SKIPLIST_NEW_HEIGHT_HPP
|
||||
#define MEMGRAPH_DATA_STRUCTURES_SKIPLIST_NEW_HEIGHT_HPP
|
||||
|
||||
#include "utils/random/xorshift.hpp"
|
||||
|
||||
size_t new_height(int max_height)
|
||||
{
|
||||
// get 64 random bits (coin tosses)
|
||||
uint64_t rand = xorshift::next();
|
||||
size_t height = 0;
|
||||
|
||||
// for every head (1) increase the tower height by one until the tail (0)
|
||||
// comes. this gives the following probabilities for tower heights:
|
||||
//
|
||||
// 1/2 1/4 1/8 1/16 1/32 1/64 ...
|
||||
// 1 2 3 4 5 6 ...
|
||||
//
|
||||
while(max_height-- && ((rand >>= 1) & 1))
|
||||
height++;
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
#endif
|
82
data_structures/skiplist/skiplist.hpp
Normal file
82
data_structures/skiplist/skiplist.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef MEMGRAPH_DATA_STRUCTURES_SKIPLIST_HPP
|
||||
#define MEMGRAPH_DATA_STRUCTURES_SKIPLIST_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <array>
|
||||
|
||||
#include "utils/random/xorshift.hpp"
|
||||
|
||||
size_t new_height(int max_height)
|
||||
{
|
||||
uint64_t rand = xorshift::next();
|
||||
size_t height = 0;
|
||||
|
||||
while(max_height-- && (rand >>= 1) & 1)
|
||||
height++;
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
template <class K, class T>
|
||||
struct SkipNode
|
||||
{
|
||||
SkipNode(K* key, T* item)
|
||||
: key(key), item(item) {}
|
||||
|
||||
K* key;
|
||||
T* item;
|
||||
|
||||
SkipNode* up;
|
||||
SkipNode* forward;
|
||||
};
|
||||
|
||||
template <class K,
|
||||
class T,
|
||||
size_t height = 16>
|
||||
class SkipList
|
||||
{
|
||||
using Node = SkipNode<K, T>;
|
||||
using Tower = std::array<Node, height>;
|
||||
|
||||
public:
|
||||
SkipList()
|
||||
{
|
||||
head.fill(nullptr);
|
||||
}
|
||||
|
||||
T* get(const K* const key)
|
||||
{
|
||||
size_t h = height;
|
||||
|
||||
while(h--)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void put(const K* key, T* item)
|
||||
{
|
||||
auto* node = new SkipNode<T, K>(key, item);
|
||||
|
||||
Tower trace;
|
||||
|
||||
size_t h = height - 1;
|
||||
|
||||
while(h--)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void del(const K* const key)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
Tower head;
|
||||
};
|
||||
|
||||
#endif
|
44
test/skiplist.cpp
Normal file
44
test/skiplist.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "data_structures/skiplist/new_height.hpp"
|
||||
|
||||
TEST_CASE("New height distribution must be approx. 1/2 1/4 1/8 ...")
|
||||
{
|
||||
// NEVER forget to do this.
|
||||
xorshift::init();
|
||||
|
||||
constexpr int N = 1e8;
|
||||
constexpr int max_height = 8;
|
||||
|
||||
// 2% is a good margin to start with, no?
|
||||
// depends on the max_height and N, beware.
|
||||
constexpr double error_margin = 0.02;
|
||||
|
||||
// array to store the number of i-height towers generated
|
||||
std::array<int, max_height> heights;
|
||||
heights.fill(0);
|
||||
|
||||
// generate a tower and put it in a box with his same-height brothers
|
||||
for(int i = 0; i < N; ++i)
|
||||
heights[new_height(max_height)]++;
|
||||
|
||||
// evaluate the number of towers in all of the boxes
|
||||
for(int i = 0; i < max_height; ++i)
|
||||
{
|
||||
// compute how much towers should be in this box
|
||||
int x = N / (2 << i);
|
||||
|
||||
// the actual number of towers
|
||||
int xx = heights[i];
|
||||
|
||||
// relative error
|
||||
double relative_error = (double)std::abs(xx - x) / xx;
|
||||
|
||||
// this might fail actually in some cases, especially if N is not big
|
||||
// enough. it's probabilistic after all :D
|
||||
REQUIRE(relative_error < error_margin);
|
||||
}
|
||||
}
|
@ -6,7 +6,19 @@
|
||||
|
||||
namespace xorshift
|
||||
{
|
||||
static uint64_t x, y, z;
|
||||
static uint64_t s[2];
|
||||
|
||||
uint64_t avalance(uint64_t s)
|
||||
{
|
||||
// MurmurHash3 finalizer
|
||||
s ^= s >> 33;
|
||||
s *= 0xff51afd7ed558ccd;
|
||||
s ^= s >> 33;
|
||||
s *= 0xc4ceb9fe1a85ec53;
|
||||
s ^= s >> 33;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
@ -16,23 +28,23 @@ namespace xorshift
|
||||
std::mt19937_64 gen(rd());
|
||||
std::uniform_int_distribution<unsigned long long> dist;
|
||||
|
||||
x = dist(gen);
|
||||
y = dist(gen);
|
||||
z = dist(gen);
|
||||
// the number generated by MT can be full of zeros and xorshift
|
||||
// doesn't like this so we use MurmurHash3 64bit finalizer to
|
||||
// make it less biased
|
||||
|
||||
s[0] = avalance(dist(gen));
|
||||
s[1] = avalance(dist(gen));
|
||||
}
|
||||
|
||||
uint64_t next()
|
||||
{
|
||||
// period 2^96 - 1
|
||||
uint64_t t;
|
||||
uint64_t s1 = s[0];
|
||||
const uint64_t s0 = s[1];
|
||||
|
||||
x ^= x << 16;
|
||||
x ^= x >> 5;
|
||||
x ^= x << 1;
|
||||
s[0] = s0;
|
||||
s1 ^= s1 << 23;
|
||||
|
||||
t = x, x = y, y = z;
|
||||
|
||||
return t ^ x ^ y;
|
||||
return (s[1] = (s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26))) + s0;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user