From 72c97822776ddfac806814a31776088485e5fb8f Mon Sep 17 00:00:00 2001 From: Yan Date: Thu, 25 Jul 2019 13:17:03 -0400 Subject: [PATCH 1/5] initial header and test file for treap --- src/streamingcc_include/treap.h | 69 +++++++++++++++++++++++++++++++++ tests/treap_test.cc | 28 +++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 src/streamingcc_include/treap.h create mode 100644 tests/treap_test.cc diff --git a/src/streamingcc_include/treap.h b/src/streamingcc_include/treap.h new file mode 100644 index 00000000..b7b59841 --- /dev/null +++ b/src/streamingcc_include/treap.h @@ -0,0 +1,69 @@ +#ifndef STREAMINGCC_TREAP_H +#define STREAMINGCC_TREAP_H + +#include +#include + +namespace streamingcc { + +template +// struct for tree node to store single data of +// any comparable type +struct treeNode { + treeNode* parent; + treeNode* lc; + treeNode* rc; + T value; + int height; + double priority; + + // Constructor + treeNode() { + parent = nullptr; + lc = nullptr; + rc = nullptr; + height = 0; + } + treeNode(T value, int height, double priority) { + treeNode(); + this->value = value; + this->height = height; + this->priority = priority; + } +}; + +template +class Treap { + // Private data in treap + treeNode* root; + int _size; + + // Private operations + // Rotation + void rotate(treeNode* tn); + void rotate_left(treeNode* tn); + void rotate_right(treeNode* tn); + + // Insertion below a treeNode + treeNode* insert(treeNode* tn, T val); + + // Helper functions + void assignPriority(treeNode* tn); + void updateHeight(treeNode* tn); + void adjustPriority(treeNode* tn); + +public: + // Constructor + Treap() { + this->root = new treeNode(); + this->_size = 0; + } + // Deconstructor + ~Treap() {}; + + void insert(T val) { insert(this->root, val); }; + treeNode* find(T val); +}; + +} +#endif //STREAMINGCC_TREAP_H diff --git a/tests/treap_test.cc b/tests/treap_test.cc new file mode 100644 index 00000000..4603e819 --- /dev/null +++ b/tests/treap_test.cc @@ -0,0 +1,28 @@ +#include "../src/streamingcc_include/treap.h" +#include +#include +#include +#include + +#define BOOST_TEST_MODULE ClassTest +#define BOOST_TEST_DYN_LINK + +BOOST_AUTO_TEST_CASE(Treap_test) { + using streamingcc::Treap; + + int n = 1e6; + Treap treap; + // Insert 1e6 elements into treap + for (int i = 0; i < n; i++) { + treap.insert(i); + } + + // Random select 5 elements to check + // if these elements are in treap + srand(time(nullptr)); + for (int i = 0; i < 5; i++) { + int j = std::rand() % n; + BOOST_CHECK(treap.find(j)->value == j); + BOOST_CHECK_MESSAGE(); + } +}; From 1b07851b09ac52c4f3c0b31bba272a8e56c4b189 Mon Sep 17 00:00:00 2001 From: Yan Date: Thu, 25 Jul 2019 14:26:24 -0400 Subject: [PATCH 2/5] replace find by contains; passed cpplint check --- src/streamingcc_include/treap.h | 27 +++++++++++++++++---------- tests/treap_test.cc | 2 ++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/streamingcc_include/treap.h b/src/streamingcc_include/treap.h index b7b59841..3b57485b 100644 --- a/src/streamingcc_include/treap.h +++ b/src/streamingcc_include/treap.h @@ -1,8 +1,11 @@ -#ifndef STREAMINGCC_TREAP_H -#define STREAMINGCC_TREAP_H +// Copyright 2019 Yan Song + +#ifndef SRC_STREAMINGCC_INCLUDE_TREAP_H_ +#define SRC_STREAMINGCC_INCLUDE_TREAP_H_ #include #include +#include namespace streamingcc { @@ -44,26 +47,30 @@ class Treap { void rotate_left(treeNode* tn); void rotate_right(treeNode* tn); - // Insertion below a treeNode + // Underlying insertion and searching treeNode* insert(treeNode* tn, T val); + bool contains(treeNode* tn, T val); // Helper functions void assignPriority(treeNode* tn); void updateHeight(treeNode* tn); void adjustPriority(treeNode* tn); -public: + // Clear treap + void destroyRecursive(treeNode* tn); + + public: // Constructor Treap() { this->root = new treeNode(); this->_size = 0; } - // Deconstructor - ~Treap() {}; + // Destructor + ~Treap() { destroyRecursive(this->root); } - void insert(T val) { insert(this->root, val); }; - treeNode* find(T val); + void insert(T val) { insert(this->root, val); } + bool contains(T val) { return contains(this->root, val); } }; -} -#endif //STREAMINGCC_TREAP_H +} // namespace streamingcc +#endif // SRC_STREAMINGCC_INCLUDE_TREAP_H_ diff --git a/tests/treap_test.cc b/tests/treap_test.cc index 4603e819..5988a75f 100644 --- a/tests/treap_test.cc +++ b/tests/treap_test.cc @@ -1,3 +1,5 @@ +// Copyright 2019 Yan Song + #include "../src/streamingcc_include/treap.h" #include #include From 05443d1f640b7ced2df7d87d896fd6902eeb050e Mon Sep 17 00:00:00 2001 From: Yan Date: Thu, 25 Jul 2019 14:51:14 -0400 Subject: [PATCH 3/5] add treap on setup.py --- python/setup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/setup.py b/python/setup.py index 8773cc75..d919439c 100644 --- a/python/setup.py +++ b/python/setup.py @@ -36,6 +36,13 @@ include_dirs = ['../src/streamingcc_include/'], extra_compile_args=['-std=c++11'], language='c++' + ), + Extension( + 'streamingcc._treap', + sources=['streamingcc/_treap.pyx'] + all_cc_files, + include_dirs = ['../src/streamingcc_include/'], + extra_compile_args=['-std=c++11'], + language='c++' ) ] From 22105e93bcd0de9ddb0ce5eb152700ea6fe4c084 Mon Sep 17 00:00:00 2001 From: Yan Date: Fri, 26 Jul 2019 13:03:24 -0400 Subject: [PATCH 4/5] add treap implementation --- src/streamingcc | 1 + src/streamingcc_include/treap.h | 17 ++- src/treap.cc | 185 ++++++++++++++++++++++++++++++++ tests/treap_test.cc | 59 ++++++---- 4 files changed, 229 insertions(+), 33 deletions(-) create mode 100644 src/treap.cc diff --git a/src/streamingcc b/src/streamingcc index 7df65ed9..3e495989 100644 --- a/src/streamingcc +++ b/src/streamingcc @@ -10,5 +10,6 @@ #include "streamingcc_include/sampling.h" #include "streamingcc_include/bloom_filter.h" #include "streamingcc_include/hyper_loglog.h" +#include "streamingcc_include/treap.h" #endif // SRC_STREAMINGCC diff --git a/src/streamingcc_include/treap.h b/src/streamingcc_include/treap.h index 3b57485b..61099d41 100644 --- a/src/streamingcc_include/treap.h +++ b/src/streamingcc_include/treap.h @@ -3,9 +3,7 @@ #ifndef SRC_STREAMINGCC_INCLUDE_TREAP_H_ #define SRC_STREAMINGCC_INCLUDE_TREAP_H_ -#include -#include -#include +#include "../streamingcc_include/util.h" namespace streamingcc { @@ -13,6 +11,7 @@ template // struct for tree node to store single data of // any comparable type struct treeNode { + public: treeNode* parent; treeNode* lc; treeNode* rc; @@ -27,12 +26,6 @@ struct treeNode { rc = nullptr; height = 0; } - treeNode(T value, int height, double priority) { - treeNode(); - this->value = value; - this->height = height; - this->priority = priority; - } }; template @@ -62,8 +55,8 @@ class Treap { public: // Constructor Treap() { - this->root = new treeNode(); - this->_size = 0; + root = new treeNode(); + _size = 0; } // Destructor ~Treap() { destroyRecursive(this->root); } @@ -72,5 +65,7 @@ class Treap { bool contains(T val) { return contains(this->root, val); } }; + } // namespace streamingcc #endif // SRC_STREAMINGCC_INCLUDE_TREAP_H_ + diff --git a/src/treap.cc b/src/treap.cc new file mode 100644 index 00000000..0e242b57 --- /dev/null +++ b/src/treap.cc @@ -0,0 +1,185 @@ +// Copyright 2019 Yan Song + +#include "streamingcc_include/treap.h" + +using streamingcc::util::rand_double; + +namespace streamingcc { + +// Underlying insertion and searching +template +bool Treap::contains(treeNode* tn, T val) { + // base case + if (tn == nullptr) return false; + // hit + if (tn->value == val) return true; + // Go to left subtree + if (tn->value > val) return contains(tn->lc, val); + // Go to right subtree + return contains(tn->rc, val); +} + +template +treeNode* Treap::insert(treeNode* tn, T val) { + // Empty tree + if (_size == 0) { + root->value = val; + assignPriority(root); + _size++; + return root; + } + + // Insert to the left + if (tn->value >= val) { + if (tn->lc == nullptr) { + // Create a new left child + treeNode* nlc = new treeNode(); + _size++; + assignPriority(nlc); + nlc->value = val; + // Connect nlc to tree + nlc->parent = tn; + tn->lc = nlc; + // Adjust height and priority + nlc->height = 0; + updateHeight(tn); + adjustPriority(nlc); + return nlc; + } + return insert(tn->lc, val); + } + + // Insert to the right + if (tn->rc == nullptr) { + // Create a new right child + treeNode* nrc = new treeNode(); + _size++; + assignPriority(nrc); + nrc->value = val; + // Connect nrc to tree + nrc->parent = tn; + tn->rc = nrc; + // Adjust height + nrc->height = 0; + updateHeight(tn); + adjustPriority(nrc); + return nrc; + } + return insert(tn->rc, val); +} + +// Rotation +template +void Treap::rotate(treeNode *tn) { + if (tn->parent == nullptr) return; + if (tn->parent->lc == tn) return rotate_right(tn); + return rotate_left(tn); +} + +template +void Treap::rotate_left(treeNode *y) { + treeNode* x = y->parent; + treeNode* z = y->lc; + + // Take care of x's parent + if (x->parent == nullptr) { + this->root = y; + } else if (x->parent->lc == x) { + x->parent->lc = y; + } else { + x->parent->rc = y; + } + + // work on y + y->parent = x->parent; + y->lc = x; + + // work on x + x->parent = y; + x->rc = z; + + // work on z + if (z != nullptr) z->parent = x; + + updateHeight(y); + updateHeight(x); +} + +template +void Treap::rotate_right(treeNode *x) { + treeNode* y = x->parent; + treeNode* z = x->rc; + + // Take care of y's parent + if (y->parent == nullptr) { + this->root = x; + } else if (y->parent->lc == y) { + y->parent->lc = x; + } else { + y->parent->rc = x; + } + + // work on x + x->parent = y->parent; + x->rc = y; + + // work on y + y->parent = x; + y->lc = z; + + // work on z + if (z != nullptr) z->parent = y; + + updateHeight(x); + updateHeight(y); +} + +// Helper functions +template +void Treap::updateHeight(treeNode *tn) { + if (tn == nullptr) return; + + int oldHeight = tn->height; + int newHeight = 0; + if (tn->lc == nullptr && tn->rc == nullptr) newHeight = 0; + else if (tn->lc == nullptr) newHeight = tn->rc->height + 1; + else if (tn->rc == nullptr) newHeight = tn->lc->height + 1; + else if (tn->lc->height > tn->rc->height) + newHeight = tn->lc->height + 1; + else + newHeight = tn->rc->height + 1; + + if (newHeight == oldHeight) { + return; + } else { + tn->height = newHeight; + updateHeight(tn->parent); + } +} + +template +void Treap::adjustPriority(treeNode *x) { + while (x->parent != nullptr && x->priority > x->parent->priority) { + rotate(x); + } +} + +template +void Treap::assignPriority(treeNode* tn) { + double randomPriority = rand_double(1.0); + if (static_cast(randomPriority) == 1) assignPriority(tn); + else + tn->priority = randomPriority; +} + +template +void Treap::destroyRecursive(treeNode* tn) { + if (tn == nullptr) + return; + + destroyRecursive(tn->lc); + destroyRecursive(tn->rc); + delete tn; +} + +} // namespace streamingcc diff --git a/tests/treap_test.cc b/tests/treap_test.cc index 5988a75f..fc367b7d 100644 --- a/tests/treap_test.cc +++ b/tests/treap_test.cc @@ -1,30 +1,45 @@ // Copyright 2019 Yan Song #include "../src/streamingcc_include/treap.h" -#include -#include -#include -#include - +#include "../src/treap.cc" #define BOOST_TEST_MODULE ClassTest #define BOOST_TEST_DYN_LINK -BOOST_AUTO_TEST_CASE(Treap_test) { - using streamingcc::Treap; +#include + +using streamingcc::Treap; +using streamingcc::util::rand_int; + +BOOST_AUTO_TEST_CASE(Treap_Test) { + int n = 100000; + Treap treap; + // Insert 1e6 elements into treap + for (int i = 0; i < n; i++) { + treap.insert(i); + } + + // Random select 5 elements to check + // if these elements are in treap + for (int i = 0; i < 5; i++) { + int j = rand_int(n); + BOOST_CHECK(treap.contains(j)); + } + BOOST_CHECK(!treap.contains(n)); +} - int n = 1e6; - Treap treap; - // Insert 1e6 elements into treap - for (int i = 0; i < n; i++) { - treap.insert(i); - } +BOOST_AUTO_TEST_CASE(Treap_Test_Reverse) { + int n = 1000000; + Treap treap; + // Insert 1e6 elements into treap + for (int i = n-1; i >= 0; i--) { + treap.insert(i); + } - // Random select 5 elements to check - // if these elements are in treap - srand(time(nullptr)); - for (int i = 0; i < 5; i++) { - int j = std::rand() % n; - BOOST_CHECK(treap.find(j)->value == j); - BOOST_CHECK_MESSAGE(); - } -}; + // Random select 5 elements to check + // if these elements are in treap + for (int i = 0; i < 5; i++) { + int j = rand_int(n); + BOOST_CHECK(treap.contains(j)); + } + BOOST_CHECK(!treap.contains(n)); +} From 8dedf7d342c76a4a306aab7803ba41b2ea7b5ee9 Mon Sep 17 00:00:00 2001 From: Yan Date: Fri, 26 Jul 2019 13:18:41 -0400 Subject: [PATCH 5/5] add python wrapper --- python/streamingcc/_treap.pyx | 19 +++++++++++++++++++ python/streamingcc/treap.py | 13 +++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 python/streamingcc/_treap.pyx create mode 100644 python/streamingcc/treap.py diff --git a/python/streamingcc/_treap.pyx b/python/streamingcc/_treap.pyx new file mode 100644 index 00000000..d394cfdc --- /dev/null +++ b/python/streamingcc/_treap.pyx @@ -0,0 +1,19 @@ +# distutils: language = c++ +# distutils: sources = ../src/treap.cc +from libcpp cimport bool + +cdef extern from "../../src/streamingcc_include/treap.h" namespace "streamingcc": + cdef cppclass Treap: + Treap() except + + void insert(int val) + bool contains(int val) + +cdef class PyTreap: + cdef Treap treap + def __cint__(self): + self.treap = Treap() + def insert(self, val): + self.treap.insert(val) + def contains(self, val): + self.treap.contains(val) + diff --git a/python/streamingcc/treap.py b/python/streamingcc/treap.py new file mode 100644 index 00000000..2db2ea57 --- /dev/null +++ b/python/streamingcc/treap.py @@ -0,0 +1,13 @@ +import streamingcc._treap as _treap + +Treap = _treap.PyTreap + +class TP: + def __init__(self): + self._tp = Treap() + + def insert(self, val): + self._tp.insert(val) + + def contains(self, val): + self._tp.contains(val)