├── .gitignore ├── avl-tree-config.cmake.in ├── tests ├── tests.cmake ├── tree.copy.cpp ├── tree.copy_assign.cpp ├── tree.clear.cpp ├── tree.move.cpp ├── tree.move_assign.cpp ├── tree.swap.cpp ├── tree.equality.cpp ├── basic.random_insert_remove.cpp ├── iterators.dereference.cpp ├── iterators.ordering.cpp ├── traits.comparable.cpp └── traits.ordering.cpp ├── avl_test.hpp ├── avl_test.cpp ├── avl_traits.hpp ├── README.md ├── CMakeLists.txt ├── LICENSE └── avl_tree.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /avl-tree-config.cmake.in: -------------------------------------------------------------------------------- 1 | set(AVL_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/include) 2 | -------------------------------------------------------------------------------- /tests/tests.cmake: -------------------------------------------------------------------------------- 1 | set(AVL_TEST_LIST 2 | ${PROJECT_SOURCE_DIR}/tests/basic.random_insert_remove.cpp 3 | ${PROJECT_SOURCE_DIR}/tests/iterators.dereference.cpp 4 | ${PROJECT_SOURCE_DIR}/tests/iterators.ordering.cpp 5 | ${PROJECT_SOURCE_DIR}/tests/tree.clear.cpp 6 | ${PROJECT_SOURCE_DIR}/tests/tree.copy_assign.cpp 7 | ${PROJECT_SOURCE_DIR}/tests/tree.copy.cpp 8 | ${PROJECT_SOURCE_DIR}/tests/tree.equality.cpp 9 | ${PROJECT_SOURCE_DIR}/tests/tree.move_assign.cpp 10 | ${PROJECT_SOURCE_DIR}/tests/tree.move.cpp 11 | ${PROJECT_SOURCE_DIR}/tests/tree.swap.cpp 12 | ${PROJECT_SOURCE_DIR}/tests/traits.ordering.cpp 13 | ${PROJECT_SOURCE_DIR}/tests/traits.comparable.cpp 14 | ) 15 | -------------------------------------------------------------------------------- /avl_test.hpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #pragma once 15 | #include "avl_tree.hpp" 16 | #include 17 | #include 18 | 19 | using namespace std; 20 | 21 | void random_double_fill(AVL::tree&, const unsigned); 22 | -------------------------------------------------------------------------------- /tests/tree.copy.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(tree, copy) { 17 | AVL::tree t; 18 | const unsigned N = 10000; 19 | random_double_fill(t, N); 20 | 21 | AVL::tree s(t); 22 | ASSERT_EQ(t, s); 23 | 24 | mt19937 rng; 25 | uniform_real_distribution uniform; 26 | int r = (int)(s.size() * uniform(rng)); 27 | s.erase(s.at(r)); 28 | ASSERT_TRUE(t != s); 29 | } 30 | -------------------------------------------------------------------------------- /tests/tree.copy_assign.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(tree, copy_assign) { 17 | AVL::tree t; 18 | const unsigned N = 10000; 19 | random_double_fill(t, N); 20 | 21 | AVL::tree s = t; 22 | ASSERT_EQ(t, s); 23 | 24 | mt19937 rng; 25 | uniform_real_distribution uniform; 26 | int r = (int)(s.size() * uniform(rng)); 27 | s.erase(s.at(r)); 28 | ASSERT_TRUE(t != s); 29 | } 30 | -------------------------------------------------------------------------------- /tests/tree.clear.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(tree, clear) { 17 | AVL::tree t; 18 | const unsigned N = 10000; 19 | 20 | random_double_fill(t, N); 21 | ASSERT_FALSE(t.empty()); 22 | ASSERT_EQ(N, t.size()); 23 | 24 | t.clear(); 25 | ASSERT_TRUE(t.empty()); 26 | ASSERT_EQ(0, t.size()); 27 | 28 | random_double_fill(t, N); 29 | ASSERT_FALSE(t.empty()); 30 | ASSERT_EQ(N, t.size()); 31 | } 32 | -------------------------------------------------------------------------------- /avl_test.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "avl_test.hpp" 15 | 16 | void random_double_fill(AVL::tree &t, const unsigned N) { 17 | mt19937 rng; 18 | uniform_real_distribution uniform; 19 | 20 | // fill with random numbers 21 | size_t i; 22 | for (i = 0; i < N; i++) { 23 | t.insert(uniform(rng)); 24 | } 25 | } 26 | 27 | int main(int argc, char *argv[]) { 28 | testing::InitGoogleTest(&argc, argv); 29 | return RUN_ALL_TESTS(); 30 | } 31 | -------------------------------------------------------------------------------- /tests/tree.move.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | #include 16 | 17 | TEST(tree, move) { 18 | AVL::tree t; 19 | const unsigned N = 10000; 20 | random_double_fill(t, N); 21 | 22 | // copy first 23 | AVL::tree t2(t); 24 | 25 | AVL::tree s(std::move(t2)); 26 | ASSERT_EQ(t, s); 27 | 28 | mt19937 rng; 29 | uniform_real_distribution uniform; 30 | int r = (int)(s.size() * uniform(rng)); 31 | s.erase(s.at(r)); 32 | ASSERT_TRUE(t != s); 33 | } 34 | -------------------------------------------------------------------------------- /tests/tree.move_assign.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | #include 16 | 17 | TEST(tree, move_assign) { 18 | AVL::tree t; 19 | const unsigned N = 10000; 20 | random_double_fill(t, N); 21 | 22 | // copy first 23 | AVL::tree t2(t); 24 | 25 | // move 26 | AVL::tree s = std::move(t2); 27 | ASSERT_EQ(t, s); 28 | 29 | mt19937 rng; 30 | uniform_real_distribution uniform; 31 | int r = (int)(s.size() * uniform(rng)); 32 | s.erase(s.at(r)); 33 | ASSERT_TRUE(t != s); 34 | } 35 | -------------------------------------------------------------------------------- /tests/tree.swap.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(tree, swap) { 17 | AVL::tree t, s; 18 | const unsigned N = 10000; 19 | random_double_fill(t, N); 20 | random_double_fill(s, 2*N); 21 | 22 | // copy first 23 | AVL::tree t2(t); 24 | AVL::tree s2(s); 25 | 26 | ASSERT_TRUE(t2 == t); 27 | ASSERT_FALSE(t2 == s); 28 | 29 | t2.swap(s2); 30 | ASSERT_FALSE(t2 == t); 31 | ASSERT_TRUE(t2 == s); 32 | 33 | swap(s2, t2); 34 | ASSERT_TRUE(t2 == t); 35 | ASSERT_FALSE(t2 == s); 36 | } 37 | -------------------------------------------------------------------------------- /avl_traits.hpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #pragma once 15 | #include 16 | 17 | namespace AVL { 18 | template using void_t = void; 19 | 20 | 21 | template 22 | struct defines_ordering : std::false_type {}; 23 | 24 | template 25 | struct defines_ordering> 26 | : std::true_type {}; 27 | 28 | 29 | template 30 | struct is_comparable : std::false_type {}; 31 | 32 | template 33 | struct is_comparable> 34 | : std::true_type {}; 35 | } 36 | -------------------------------------------------------------------------------- /tests/tree.equality.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(tree, equality) { 17 | AVL::tree t, s; 18 | const unsigned N = 1000; 19 | random_double_fill(t, N); 20 | 21 | AVL::tree::const_iterator it; 22 | for (it = t.cbegin(); it != t.cend(); ++it) { 23 | s.insert(*it); 24 | } 25 | 26 | ASSERT_EQ(s, t); 27 | ASSERT_EQ(t, s); 28 | ASSERT_FALSE(s != t); 29 | ASSERT_FALSE(t != s); 30 | 31 | mt19937 rng; 32 | uniform_real_distribution uniform; 33 | int r = (int)(t.size() * uniform(rng)); 34 | s.erase(s.at(r)); 35 | ASSERT_TRUE(s != t); 36 | ASSERT_TRUE(t != s); 37 | ASSERT_FALSE(s == t); 38 | ASSERT_FALSE(t == s); 39 | } 40 | -------------------------------------------------------------------------------- /tests/basic.random_insert_remove.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(basic, random_insert_remove) { 17 | AVL::tree t; 18 | const unsigned N = 10000; 19 | 20 | random_double_fill(t, N); 21 | 22 | // check ordering and consistent indices/iterators 23 | AVL::tree::const_iterator it; 24 | double last = 0.; 25 | size_t i; 26 | for (it = t.begin(), i = 0; it != t.end(); ++it, ++i) { 27 | ASSERT_EQ(*it, t[i]); 28 | ASSERT_EQ(true, last <= *it); 29 | last = *it; 30 | } 31 | 32 | // randomly pick elements and delete 33 | mt19937 rng; 34 | uniform_real_distribution uniform; 35 | AVL::tree::iterator it2; 36 | size_t d; 37 | for (size_t i = 0; i < N; i++) { 38 | // check again half-way in 39 | if (i == N/2) { 40 | last = 0.; 41 | for (it = t.begin(), i = 0; it != t.end(); it++, ++i) { 42 | ASSERT_EQ(*it, t[i]); 43 | ASSERT_EQ(true, last <= *it); 44 | last = *it; 45 | } 46 | } 47 | 48 | d = (size_t)(t.size() * uniform(rng)); 49 | it2 = t.at(d); 50 | t.erase(it2); 51 | } 52 | ASSERT_EQ(0, t.size()); 53 | } 54 | -------------------------------------------------------------------------------- /tests/iterators.dereference.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(iterators, dereference) { 17 | AVL::tree t; 18 | const unsigned N = 1000; 19 | random_double_fill(t, N); 20 | 21 | struct wrapper { 22 | double data; 23 | wrapper() {}; 24 | wrapper(const double d) : data(d) {}; 25 | bool operator<(const wrapper &o) const { return data < o.data; } 26 | bool operator>(const wrapper &o) const { return data > o.data; } 27 | bool operator<=(const wrapper &o) const { return data <= o.data; } 28 | bool operator>=(const wrapper &o) const { return data >= o.data; } 29 | bool operator==(const wrapper &o) const { return data == o.data; } 30 | bool operator!=(const wrapper &o) const { return data != o.data; } 31 | }; 32 | 33 | AVL::tree w; 34 | AVL::tree::const_iterator it; 35 | for (it = t.cbegin(); it != t.cend(); ++it) { 36 | w.insert(wrapper(*it)); 37 | } 38 | AVL::tree::const_iterator wit; 39 | for (it = t.cbegin(), wit = w.cbegin(); it != t.cend(); ++it, ++wit) { 40 | ASSERT_EQ(*it, wit->data); 41 | } 42 | ASSERT_EQ(wit, w.cend()); 43 | 44 | const AVL::tree& wc = w; 45 | ASSERT_EQ(w.front(), *w.begin()); 46 | ASSERT_EQ(w.back(), *(--w.end())); 47 | ASSERT_EQ(wc.front(), *wc.begin()); 48 | ASSERT_EQ(wc.back(), *(--wc.end())); 49 | } 50 | -------------------------------------------------------------------------------- /tests/iterators.ordering.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | 16 | TEST(iterators, ordering) { 17 | AVL::tree t; 18 | const unsigned N = 100; 19 | random_double_fill(t, N); 20 | AVL::tree::iterator iit1; 21 | AVL::tree::const_iterator it2; 22 | for (iit1 = t.begin(); iit1 != t.end(); ++iit1) { 23 | bool passed = false; 24 | AVL::tree::const_iterator it1(iit1); 25 | for (it2 = --t.end(); it2 != t.begin(); it2--) { 26 | if (it1 == it2) { 27 | ASSERT_TRUE(*it1 == *it2); 28 | ASSERT_FALSE(it1 != it2); 29 | ASSERT_FALSE(passed); 30 | passed = true; 31 | ASSERT_FALSE(it1 < it2); 32 | ASSERT_FALSE(it1 > it2); 33 | ASSERT_TRUE(it1 <= it2); 34 | ASSERT_TRUE(it1 >= it2); 35 | } else { 36 | ASSERT_FALSE(*it1 == *it2); 37 | ASSERT_TRUE(it1 != it2); 38 | if (passed) { 39 | ASSERT_FALSE(it1 < it2); 40 | ASSERT_FALSE(it1 <= it2); 41 | ASSERT_TRUE(it1 > it2); 42 | ASSERT_TRUE(it1 >= it2); 43 | } else { 44 | ASSERT_TRUE(it1 < it2); 45 | ASSERT_TRUE(it1 <= it2); 46 | ASSERT_FALSE(it1 > it2); 47 | ASSERT_FALSE(it1 >= it2); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/traits.comparable.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | #include "../avl_traits.hpp" 16 | #include 17 | #include 18 | 19 | const size_t N = 100; 20 | 21 | class data_t { 22 | private: 23 | double *payload; 24 | double sum() const { 25 | double s = 0; 26 | for (size_t i = 0; i < N; ++i) 27 | s += payload[i]; 28 | return s; 29 | } 30 | public: 31 | data_t() { 32 | payload = new double[N]; 33 | for (size_t i = 0; i < N; ++i) 34 | payload[i] = 0.; 35 | } 36 | data_t(const data_t& d) { 37 | payload = new double[N]; 38 | for (size_t i = 0; i < N; ++i) 39 | payload[i] = d.payload[i]; 40 | } 41 | ~data_t() { 42 | delete[] payload; 43 | } 44 | bool operator<(const data_t& d) const { 45 | return sum() < d.sum(); 46 | } 47 | bool operator==(const data_t& d) const { 48 | bool res = true; 49 | for (size_t i = 0; i < N; ++i) 50 | res &= (payload[i] == d.payload[i]); 51 | return res; 52 | } 53 | }; 54 | 55 | class dumb_data_t {}; 56 | 57 | 58 | TEST(traits, comparable) { 59 | ASSERT_TRUE(AVL::is_comparable::value); 60 | ASSERT_TRUE(AVL::is_comparable::value); 61 | ASSERT_FALSE(AVL::is_comparable::value); 62 | ASSERT_TRUE(AVL::is_comparable>::value); 63 | } 64 | -------------------------------------------------------------------------------- /tests/traits.ordering.cpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #include "../avl_test.hpp" 15 | #include "../avl_traits.hpp" 16 | #include 17 | #include 18 | 19 | const size_t N = 100; 20 | 21 | class data_t { 22 | private: 23 | double *payload; 24 | double sum() const { 25 | double s = 0; 26 | for (size_t i = 0; i < N; ++i) 27 | s += payload[i]; 28 | return s; 29 | } 30 | public: 31 | data_t() { 32 | payload = new double[N]; 33 | for (size_t i = 0; i < N; ++i) 34 | payload[i] = 0.; 35 | } 36 | data_t(const data_t& d) { 37 | payload = new double[N]; 38 | for (size_t i = 0; i < N; ++i) 39 | payload[i] = d.payload[i]; 40 | } 41 | ~data_t() { 42 | delete[] payload; 43 | } 44 | bool operator<(const data_t& d) const { 45 | return sum() < d.sum(); 46 | } 47 | bool operator==(const data_t& d) const { 48 | bool res = true; 49 | for (size_t i = 0; i < N; ++i) 50 | res &= (payload[i] == d.payload[i]); 51 | return res; 52 | } 53 | }; 54 | 55 | class dumb_data_t {}; 56 | 57 | 58 | TEST(traits, ordering) { 59 | ASSERT_TRUE(AVL::defines_ordering::value); 60 | ASSERT_TRUE(AVL::defines_ordering::value); 61 | ASSERT_FALSE(AVL::defines_ordering::value); 62 | ASSERT_FALSE(AVL::defines_ordering>::value); 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # avl-tree 2 | A templated [AVL tree](https://en.wikipedia.org/wiki/AVL_tree) with STL-style iterators and random access; written in C++. 3 | 4 | ## Usage 5 | 6 | The template parameter needs to be of a type that is default constructible as well as copy constructible and implements an ordering via `operator<` as well as the equality `operator==`. While it is possible to obtain mutable references to elements in the tree via the `operator[]` and `find` member functions or by dereferencing mutable iterators, *it is crucial that any mutation of the tree's contents does not interfere with their relative ordering*. 7 | 8 | When storing compound data types in the tree, you may take advantage of move semantics by abiding to the *rule of five*. `insert` is overloaded to store rvalues. 9 | 10 | The example below illustrates the basic use of the tree. A more complete documentation will hopefully be provided in the future. 11 | 12 | ```c++ 13 | #include 14 | #include 15 | 16 | int main(int argc, char const *argv[]) { 17 | AVL::tree t; 18 | 19 | // insert elements to the tree 20 | t.insert(42); 21 | t.insert(17); 22 | t.insert(19); 23 | 24 | // iterate in order 25 | AVL::tree::const_iterator it; 26 | for (it = t.begin(); it != t.end(); ++it) 27 | std::cout << *it << ", "; 28 | std::cout << std::endl; 29 | 30 | // random-access elements by index 31 | std::cout << "Second smallest number: " << t[1] << std::endl; 32 | 33 | // remove element by value 34 | t.remove(19); 35 | 36 | return 0; 37 | } 38 | ``` 39 | 40 | 41 | ## Installation 42 | This project uses CMake. To install, create a `build` directory, call `cmake` and `make install`: 43 | 44 | $ cd avl-tree 45 | $ mkdir build && cd build 46 | $ cmake .. 47 | $ make install 48 | 49 | The default install location is `/usr/local/include/`. To install e.g. to `~/.local/include/` instead, use 50 | 51 | $ cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. 52 | 53 | (Note that the `include` directory is omitted in the prefix.) 54 | 55 | ### Running tests 56 | This project uses Google's [libgtest](https://github.com/google/googletest) to run various tests. If you want to contribute to this project, make sure your modifications pass all the tests before submitting a pull request (or ask for help). CMake will automatically clone the `googletest` repository in its build directory, configure and build it. To build and run the tests pertaining to `avl-tree`, run 57 | 58 | $ make test 59 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project (avl-tree CXX) 3 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 4 | 5 | set(INSTALL_CMAKE_DIR CMake) 6 | configure_file (avl-tree-config.cmake.in avl-tree-config.cmake) 7 | install (FILES ${PROJECT_BINARY_DIR}/avl-tree-config.cmake 8 | DESTINATION ${INSTALL_CMAKE_DIR}) 9 | install (FILES avl_tree.hpp avl_traits.hpp DESTINATION include) 10 | 11 | # The following Google Test setup has been derived from 12 | # http://stackoverflow.com/questions/9689183/cmake-googletest 13 | 14 | # Enable ExternalProject CMake module 15 | include(ExternalProject) 16 | 17 | # Set the build type if it isn't already 18 | if(NOT CMAKE_BUILD_TYPE) 19 | set(CMAKE_BUILD_TYPE Release) 20 | endif() 21 | 22 | # Set default ExternalProject root directory 23 | set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/ThirdParty) 24 | 25 | # Add gtest 26 | ExternalProject_Add( 27 | googletest 28 | GIT_REPOSITORY https://github.com/google/googletest 29 | GIT_TAG release-1.7.0 30 | TIMEOUT 10 31 | # Force separate output paths for debug and release builds to allow easy 32 | # identification of correct lib in subsequent TARGET_LINK_LIBRARIES commands 33 | CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} 34 | -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=DebugLibs 35 | -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=ReleaseLibs 36 | -Dgtest_force_shared_crt=ON 37 | # Disable install step 38 | INSTALL_COMMAND "" 39 | # Wrap download, configure and build steps in a script to log output 40 | LOG_DOWNLOAD ON 41 | LOG_CONFIGURE ON 42 | LOG_BUILD ON) 43 | 44 | # Specify include dir 45 | ExternalProject_Get_Property(googletest source_dir) 46 | include_directories(${source_dir}/include) 47 | 48 | # Add test executable target 49 | include(${PROJECT_SOURCE_DIR}/tests/tests.cmake) 50 | add_executable(avl_test EXCLUDE_FROM_ALL ${PROJECT_SOURCE_DIR}/avl_test.cpp 51 | ${AVL_TEST_LIST}) 52 | 53 | # Create dependency of MainTest on googletest 54 | add_dependencies(avl_test googletest) 55 | 56 | # Specify avl_test's link libraries 57 | ExternalProject_Get_Property(googletest binary_dir) 58 | set(Suffix ".a") 59 | set(Pthread "-pthread") 60 | target_link_libraries( 61 | avl_test 62 | debug ${binary_dir}/DebugLibs/${CMAKE_FIND_LIBRARY_PREFIXES}gtest${Suffix} 63 | optimized ${binary_dir}/ReleaseLibs/${CMAKE_FIND_LIBRARY_PREFIXES}gtest${Suffix} 64 | ${Pthread}) 65 | 66 | # Add a custom 'test' target that runs the googletest tests 67 | add_custom_target(test avl_test DEPENDS avl_test) 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /avl_tree.hpp: -------------------------------------------------------------------------------- 1 | // avl-tree 2 | // Copyright (C) 2015 -- 2016 Jonas Greitemann 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | #pragma once 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace AVL { 26 | 27 | template > 28 | class tree { 29 | public: 30 | typedef A allocator_type; 31 | typedef typename A::value_type value_type; 32 | typedef typename A::reference reference; 33 | typedef typename A::const_reference const_reference; 34 | typedef typename A::difference_type difference_type; 35 | typedef typename A::size_type size_type; 36 | 37 | private: 38 | class node { 39 | public: 40 | T data; 41 | short depth; 42 | size_type n; 43 | node *parent; 44 | node *left_child; 45 | node *right_child; 46 | 47 | node() noexcept 48 | : depth(1) 49 | , n(1) 50 | , left_child(nullptr) 51 | , right_child(nullptr) 52 | , parent(nullptr) {} 53 | 54 | node(const T& t) noexcept 55 | : data(t) 56 | , depth(1) 57 | , n(1) 58 | , left_child(nullptr) 59 | , right_child(nullptr) 60 | , parent(nullptr) {} 61 | 62 | node(T&& t) noexcept 63 | : data(std::move(t)) 64 | , depth(1) 65 | , n(1) 66 | , left_child(nullptr) 67 | , right_child(nullptr) 68 | , parent(nullptr) {} 69 | 70 | 71 | #ifdef DEBUGMODE 72 | void print(std::ostream& os, std::string prefix) { 73 | os << "(" << data << "," << n << "," 74 | << depth << ")" << std::endl; 75 | if (!left_child && !right_child) 76 | return; 77 | if (left_child) { 78 | os << prefix << "+---"; 79 | left_child->print(os, prefix + "| "); 80 | } else { 81 | os << prefix << "+" << std::endl; 82 | } 83 | if (right_child) { 84 | os << prefix << "+---"; 85 | right_child->print(os, prefix + " "); 86 | } else { 87 | os << prefix << "+" << std::endl; 88 | } 89 | } 90 | #endif 91 | 92 | void update_depth() { 93 | depth = 1 + std::max(left_child ? left_child->depth : 0, 94 | right_child ? right_child->depth : 0); 95 | } 96 | 97 | void update_n() { 98 | n = 1 + (left_child ? left_child->n : 0) 99 | + (right_child ? right_child->n : 0); 100 | } 101 | 102 | short imbalance() { 103 | return (right_child ? right_child->depth : 0) 104 | - (left_child ? left_child->depth : 0); 105 | } 106 | }; 107 | 108 | public: 109 | class iterator { 110 | template 111 | friend class tree::const_iterator; 112 | friend class tree; 113 | public: 114 | typedef typename A::difference_type difference_type; 115 | typedef typename A::value_type value_type; 116 | typedef typename A::reference reference; 117 | typedef typename A::pointer pointer; 118 | typedef std::bidirectional_iterator_tag iterator_category; 119 | 120 | iterator() { 121 | ptr = nullptr; 122 | } 123 | 124 | iterator(node* p) { 125 | ptr = p; 126 | } 127 | 128 | iterator(const iterator& it) { 129 | ptr = it.ptr; 130 | } 131 | 132 | iterator& operator=(const iterator& it) { 133 | ptr = it.ptr; 134 | return *this; 135 | } 136 | 137 | bool operator==(const iterator& it) const { 138 | return ptr == it.ptr; 139 | } 140 | 141 | bool operator!=(const iterator& it) const { 142 | return ptr != it.ptr; 143 | } 144 | 145 | bool operator<(const iterator& it) const { 146 | return **this < *it; 147 | } 148 | 149 | bool operator>(const iterator& it) const { 150 | return **this > *it; 151 | } 152 | 153 | bool operator<=(const iterator& it) const { 154 | return **this <= *it; 155 | } 156 | 157 | bool operator>=(const iterator& it) const { 158 | return **this >= *it; 159 | } 160 | 161 | // pre-increment 162 | iterator& operator++() { 163 | if (ptr->right_child) { 164 | ptr = ptr->right_child; 165 | while (ptr->left_child) { 166 | ptr = ptr->left_child; 167 | } 168 | } else { 169 | node* before; 170 | do { 171 | before = ptr; 172 | ptr = ptr->parent; 173 | } while (ptr && before == ptr->right_child); 174 | } 175 | return *this; 176 | } 177 | 178 | // post-increment 179 | iterator operator++(int) { 180 | iterator old(*this); 181 | ++(*this); 182 | return old; 183 | } 184 | 185 | // pre-decrement 186 | iterator& operator--() { 187 | if (ptr->left_child) { 188 | ptr = ptr->left_child; 189 | while (ptr->right_child) { 190 | ptr = ptr->right_child; 191 | } 192 | } else { 193 | node* before; 194 | do { 195 | before = ptr; 196 | ptr = ptr->parent; 197 | } while (ptr && before == ptr->left_child); 198 | } 199 | return *this; 200 | } 201 | 202 | // post-decrement 203 | iterator operator--(int) { 204 | iterator old(*this); 205 | --(*this); 206 | return old; 207 | } 208 | 209 | reference operator*() const { 210 | return ptr->data; 211 | } 212 | 213 | pointer operator->() const { 214 | return &(ptr->data); 215 | } 216 | private: 217 | node *ptr; 218 | }; 219 | 220 | class const_iterator { 221 | public: 222 | typedef typename A::difference_type difference_type; 223 | typedef typename A::value_type value_type; 224 | typedef typename A::const_reference const_reference; 225 | typedef typename A::const_pointer const_pointer; 226 | typedef std::bidirectional_iterator_tag iterator_category; 227 | 228 | const_iterator () { 229 | ptr = nullptr; 230 | } 231 | 232 | const_iterator(const node* p) { 233 | ptr = p; 234 | } 235 | 236 | const_iterator (const const_iterator& it) { 237 | ptr = it.ptr; 238 | } 239 | 240 | const_iterator (const iterator& it) { 241 | ptr = it.ptr; 242 | } 243 | 244 | const_iterator& operator=(const const_iterator& it) { 245 | ptr = it.ptr; 246 | return *this; 247 | } 248 | 249 | bool operator==(const const_iterator& it) const { 250 | return ptr == it.ptr; 251 | } 252 | 253 | bool operator!=(const const_iterator& it) const { 254 | return ptr != it.ptr; 255 | } 256 | 257 | bool operator<(const const_iterator& it) const { 258 | return **this < *it; 259 | } 260 | 261 | bool operator>(const const_iterator& it) const { 262 | return **this > *it; 263 | } 264 | 265 | bool operator<=(const const_iterator& it) const { 266 | return **this <= *it; 267 | } 268 | 269 | bool operator>=(const const_iterator& it) const { 270 | return **this >= *it; 271 | } 272 | 273 | // pre-increment 274 | const_iterator& operator++() { 275 | if (ptr->right_child) { 276 | ptr = ptr->right_child; 277 | while (ptr->left_child) { 278 | ptr = ptr->left_child; 279 | } 280 | } else { 281 | const node* before; 282 | do { 283 | before = ptr; 284 | ptr = ptr->parent; 285 | } while (ptr && before == ptr->right_child); 286 | } 287 | return *this; 288 | } 289 | 290 | // post-increment 291 | const_iterator operator++(int) { 292 | const_iterator old(*this); 293 | ++(*this); 294 | return old; 295 | } 296 | 297 | // pre-decrement 298 | const_iterator& operator--() { 299 | if (ptr->left_child) { 300 | ptr = ptr->left_child; 301 | while (ptr->right_child) { 302 | ptr = ptr->right_child; 303 | } 304 | } else { 305 | const node* before; 306 | do { 307 | before = ptr; 308 | ptr = ptr->parent; 309 | } while (ptr && before == ptr->left_child); 310 | } 311 | return *this; 312 | } 313 | 314 | // post-decrement 315 | const_iterator operator--(int) { 316 | const_iterator old(*this); 317 | --(*this); 318 | return old; 319 | } 320 | 321 | const_reference operator*() const { 322 | return (const_reference)(ptr->data); 323 | } 324 | 325 | const_pointer operator->() const { 326 | return &(ptr->data); 327 | } 328 | private: 329 | node const *ptr; 330 | }; 331 | 332 | tree() noexcept { 333 | root = alloc.allocate(1); 334 | alloc.construct(root); 335 | root->n = 0; 336 | } 337 | 338 | tree(const tree& t) noexcept { 339 | *this = t; 340 | } 341 | 342 | tree(tree&& t) noexcept { 343 | root = t.root; 344 | t.root = alloc.allocate(1); 345 | alloc.construct(t.root); 346 | t.root->n = 0; 347 | } 348 | 349 | ~tree() noexcept { 350 | clear_node(root); 351 | alloc.destroy(root); 352 | alloc.deallocate(root, 1); 353 | } 354 | 355 | tree& operator=(const tree& t) noexcept { 356 | root = deep_copy_node(t.root); 357 | return *this; 358 | } 359 | 360 | tree& operator=(tree&& t) noexcept { 361 | clear(); 362 | std::swap(root, t.root); 363 | } 364 | 365 | bool operator==(const tree& t) const { 366 | const_iterator it1, it2; 367 | for (it1 = cbegin(), it2 = t.cbegin(); 368 | it1 != cend() && it2 != t.cend(); 369 | ++it1, ++it2) { 370 | if (*it1 != *it2) 371 | return false; 372 | } 373 | if (it1 == cend() && it2 == t.cend()) { 374 | return true; 375 | } else { 376 | return false; 377 | } 378 | } 379 | 380 | bool operator!=(const tree& t) const { 381 | return !(*this == t); 382 | } 383 | 384 | iterator begin() { 385 | node *ptr = root; 386 | while (ptr->left_child) { 387 | ptr = ptr->left_child; 388 | } 389 | return iterator(ptr); 390 | } 391 | 392 | const_iterator begin() const { 393 | const node *ptr = root; 394 | while (ptr->left_child) { 395 | ptr = ptr->left_child; 396 | } 397 | return const_iterator(ptr); 398 | } 399 | 400 | const_iterator cbegin() const { 401 | const node *ptr = root; 402 | while (ptr->left_child) { 403 | ptr = ptr->left_child; 404 | } 405 | return const_iterator(ptr); 406 | } 407 | 408 | iterator end() { 409 | return iterator(root); 410 | } 411 | 412 | const_iterator end() const { 413 | return const_iterator(root); 414 | } 415 | 416 | const_iterator cend() const { 417 | return const_iterator(root); 418 | } 419 | 420 | reference front() { 421 | iterator b = begin(); 422 | return *b; 423 | } 424 | 425 | const_reference front() const { 426 | const_iterator b = begin(); 427 | return *b; 428 | } 429 | 430 | reference back() { 431 | iterator b = end(); 432 | return *(--b); 433 | } 434 | 435 | const_reference back() const { 436 | const_iterator b = end(); 437 | return *(--b); 438 | } 439 | 440 | iterator insert(const T& t) { 441 | iterator res; 442 | 443 | // descent the search tree 444 | node *parent = root; 445 | while (true) { 446 | ++parent->n; 447 | if (parent == root || t < parent->data) { 448 | if (parent->left_child) { 449 | parent = parent->left_child; 450 | } else { 451 | parent->left_child = alloc.allocate(1); 452 | alloc.construct(parent->left_child, t); 453 | parent->left_child->parent = parent; 454 | res = iterator(parent->left_child); 455 | break; 456 | } 457 | } else { 458 | if (parent->right_child) { 459 | parent = parent->right_child; 460 | } else { 461 | parent->right_child = alloc.allocate(1); 462 | alloc.construct(parent->right_child, t); 463 | parent->right_child->parent = parent; 464 | res = iterator(parent->right_child); 465 | break; 466 | } 467 | } 468 | } 469 | short branch_depth = 1; 470 | do { 471 | if (parent->depth > branch_depth) 472 | break; 473 | parent->depth = 1 + branch_depth; 474 | if (parent == root) 475 | break; 476 | if (parent->imbalance() < -1) { 477 | // check for double-rotation case 478 | if (parent->left_child->imbalance() > 0) { 479 | rotate_left(parent->left_child); 480 | } 481 | rotate_right(parent); 482 | break; 483 | } else if (parent->imbalance() > 1) { 484 | // check for double-rotation case 485 | if (parent->right_child->imbalance() < 0) { 486 | rotate_right(parent->right_child); 487 | } 488 | rotate_left(parent); 489 | break; 490 | } 491 | branch_depth = parent->depth; 492 | parent = parent->parent; 493 | } while(parent); 494 | return res; 495 | } 496 | 497 | iterator insert(T&& t) { 498 | iterator res; 499 | 500 | // descent the search tree 501 | node *parent = root; 502 | while (true) { 503 | ++parent->n; 504 | if (parent == root || t < parent->data) { 505 | if (parent->left_child) { 506 | parent = parent->left_child; 507 | } else { 508 | parent->left_child = alloc.allocate(1); 509 | alloc.construct(parent->left_child, std::move(t)); 510 | parent->left_child->parent = parent; 511 | res = iterator(parent->left_child); 512 | break; 513 | } 514 | } else { 515 | if (parent->right_child) { 516 | parent = parent->right_child; 517 | } else { 518 | parent->right_child = alloc.allocate(1); 519 | alloc.construct(parent->right_child, std::move(t)); 520 | parent->right_child->parent = parent; 521 | res = iterator(parent->right_child); 522 | break; 523 | } 524 | } 525 | } 526 | short branch_depth = 1; 527 | do { 528 | if (parent->depth > branch_depth) 529 | break; 530 | parent->depth = 1 + branch_depth; 531 | if (parent == root) 532 | break; 533 | if (parent->imbalance() < -1) { 534 | // check for double-rotation case 535 | if (parent->left_child->imbalance() > 0) { 536 | rotate_left(parent->left_child); 537 | } 538 | rotate_right(parent); 539 | break; 540 | } else if (parent->imbalance() > 1) { 541 | // check for double-rotation case 542 | if (parent->right_child->imbalance() < 0) { 543 | rotate_right(parent->right_child); 544 | } 545 | rotate_left(parent); 546 | break; 547 | } 548 | branch_depth = parent->depth; 549 | parent = parent->parent; 550 | } while(parent); 551 | return res; 552 | } 553 | 554 | iterator at(size_type i) { 555 | // bounds checking 556 | if (i >= size()) { 557 | throw std::out_of_range("tree::at out-of-range"); 558 | } 559 | 560 | size_type j = i; 561 | node *ptr = root->left_child; 562 | while (true) { 563 | if (ptr->left_child) { 564 | if (j == ptr->left_child->n) { 565 | break; 566 | } else if (j < ptr->left_child->n) { 567 | ptr = ptr->left_child; 568 | } else { 569 | j -= 1 + ptr->left_child->n; 570 | ptr = ptr->right_child; 571 | } 572 | } else { 573 | if (j == 0) { 574 | break; 575 | } else { 576 | --j; 577 | ptr = ptr->right_child; 578 | } 579 | } 580 | } 581 | return iterator(ptr); 582 | } 583 | 584 | const_iterator at(size_type i) const { 585 | // bounds checking 586 | if (i >= size()) { 587 | throw std::out_of_range("tree[] out-of-range"); 588 | } 589 | 590 | size_type j = i; 591 | const node *ptr = root->left_child; 592 | while (true) { 593 | if (ptr->left_child) { 594 | if (j == ptr->left_child->n) { 595 | break; 596 | } else if (j < ptr->left_child->n) { 597 | ptr = ptr->left_child; 598 | } else { 599 | j -= 1 + ptr->left_child->n; 600 | ptr = ptr->right_child; 601 | } 602 | } else { 603 | if (j == 0) { 604 | break; 605 | } else { 606 | --j; 607 | ptr = ptr->right_child; 608 | } 609 | } 610 | } 611 | return const_iterator(ptr); 612 | } 613 | 614 | reference operator[](size_type i) { 615 | return *at(i); 616 | } 617 | 618 | const_reference operator[](size_type i) const { 619 | return *at(i); 620 | } 621 | 622 | iterator erase(iterator it) { 623 | iterator itn(it); 624 | ++itn; 625 | node *ptr = it.ptr; 626 | node *q; 627 | if (!ptr->left_child || !ptr->right_child) { 628 | q = ptr; 629 | } else { 630 | q = itn.ptr; 631 | } 632 | node *s; 633 | if (q->left_child) { 634 | s = q->left_child; 635 | q->left_child = nullptr; 636 | } else { 637 | s = q->right_child; 638 | q->right_child = nullptr; 639 | } 640 | if (s) { 641 | s->parent = q->parent; 642 | } 643 | if (q == q->parent->left_child) { 644 | q->parent->left_child = s; 645 | } else { 646 | q->parent->right_child = s; 647 | } 648 | node *q_parent = q->parent; 649 | if (q != ptr) { 650 | q->parent = ptr->parent; 651 | if (q->parent->left_child == ptr) { 652 | q->parent->left_child = q; 653 | } else { 654 | q->parent->right_child = q; 655 | } 656 | q->left_child = ptr->left_child; 657 | if (q->left_child) 658 | q->left_child->parent = q; 659 | q->right_child = ptr->right_child; 660 | if (q->right_child) 661 | q->right_child->parent = q; 662 | q->n = ptr->n; 663 | q->depth = ptr->depth; 664 | ptr->left_child = nullptr; 665 | ptr->right_child = nullptr; 666 | } 667 | if (q_parent == ptr) { 668 | q_parent = q; 669 | } 670 | node *parent; 671 | for (parent = q_parent; parent; parent = parent->parent) { 672 | --parent->n; 673 | } 674 | for (parent = q_parent; parent; parent = parent->parent) { 675 | parent->update_depth(); 676 | if (parent == root) 677 | break; 678 | if (parent->imbalance() < -1) { 679 | // check for double-rotation case 680 | if (parent->left_child->imbalance() > 0) { 681 | rotate_left(parent->left_child); 682 | } 683 | rotate_right(parent); 684 | break; 685 | } else if (parent->imbalance() > 1) { 686 | // check for double-rotation case 687 | if (parent->right_child->imbalance() < 0) { 688 | rotate_right(parent->right_child); 689 | } 690 | rotate_left(parent); 691 | break; 692 | } 693 | } 694 | alloc.destroy(ptr); 695 | alloc.deallocate(ptr, 1); 696 | return itn; 697 | } 698 | 699 | iterator find(const_reference t) { 700 | node *ptr = root->left_child; 701 | while (ptr) { 702 | if (t == ptr->data) { 703 | return iterator(ptr); 704 | } else if (t < ptr->data) { 705 | ptr = ptr->left_child; 706 | } else { 707 | ptr = ptr->right_child; 708 | } 709 | } 710 | return end(); 711 | } 712 | 713 | void remove(const_reference t) { 714 | iterator it = find(t); 715 | if (it == end()) 716 | return; 717 | do { 718 | it = erase(it); 719 | } while(*it == t); 720 | } 721 | 722 | void clear() noexcept { 723 | clear_node(root); 724 | root->left_child = nullptr; 725 | root->n = 0; 726 | root->depth = 1; 727 | } 728 | 729 | void swap(tree& t) { 730 | std::swap(root, t.root); 731 | } 732 | 733 | size_type size() const { 734 | return root->n; 735 | } 736 | 737 | size_type max_size(); 738 | 739 | bool empty() const { 740 | return root->left_child == nullptr; 741 | } 742 | 743 | A get_allocator() { 744 | return alloc; 745 | } 746 | 747 | private: 748 | void rotate_left(node *n) { 749 | node *tmp = n->right_child->left_child; 750 | if (n == n->parent->left_child) { 751 | n->parent->left_child = n->right_child; 752 | } else { 753 | n->parent->right_child = n->right_child; 754 | } 755 | n->right_child->parent = n->parent; 756 | n->right_child->left_child = n; 757 | n->parent = n->right_child; 758 | n->right_child = tmp; 759 | if (tmp) 760 | tmp->parent = n; 761 | 762 | // update ns 763 | n->update_n(); 764 | n->parent->update_n(); 765 | 766 | // update depths 767 | do { 768 | n->update_depth(); 769 | n = n->parent; 770 | } while (n); 771 | } 772 | 773 | void rotate_right(node *n) { 774 | node *tmp = n->left_child->right_child; 775 | if (n == n->parent->left_child) { 776 | n->parent->left_child = n->left_child; 777 | } else { 778 | n->parent->right_child = n->left_child; 779 | } 780 | n->left_child->parent = n->parent; 781 | n->left_child->right_child = n; 782 | n->parent = n->left_child; 783 | n->left_child = tmp; 784 | if (tmp) 785 | tmp->parent = n; 786 | 787 | // update ns 788 | n->update_n(); 789 | n->parent->update_n(); 790 | 791 | // update depths 792 | do { 793 | n->update_depth(); 794 | n = n->parent; 795 | } while (n); 796 | } 797 | 798 | node* deep_copy_node(const node *nd) { 799 | node *cp_nd = alloc.allocate(1); 800 | alloc.construct(cp_nd, nd->data); 801 | cp_nd->n = nd->n; 802 | cp_nd->depth = nd->depth; 803 | if (nd->left_child) { 804 | cp_nd->left_child = deep_copy_node(nd->left_child); 805 | cp_nd->left_child->parent = cp_nd; 806 | } 807 | if (nd->right_child) { 808 | cp_nd->right_child = deep_copy_node(nd->right_child); 809 | cp_nd->right_child->parent = cp_nd; 810 | } 811 | return cp_nd; 812 | } 813 | 814 | void clear_node(node *nd) noexcept { 815 | if (nd->left_child) { 816 | clear_node(nd->left_child); 817 | alloc.destroy(nd->left_child); 818 | alloc.deallocate(nd->left_child, 1); 819 | } 820 | if (nd->right_child) { 821 | clear_node(nd->right_child); 822 | alloc.destroy(nd->right_child); 823 | alloc.deallocate(nd->right_child, 1); 824 | } 825 | } 826 | 827 | using NodeAlloc = typename std::allocator_traits 828 | ::template rebind_alloc; 829 | NodeAlloc alloc; 830 | node *root; 831 | 832 | #ifdef DEBUGMODE 833 | template 834 | friend std::ostream& operator<< (std::ostream&, const tree&); 835 | #endif 836 | }; 837 | 838 | template > 839 | void swap(tree& t1, tree& t2) { 840 | t1.swap(t2); 841 | } 842 | 843 | #ifdef DEBUGMODE 844 | template > 845 | std::ostream& operator<<(std::ostream& os, const tree& t) { 846 | if (!t.root->left_child) 847 | return os << "(empty)" << std::endl; 848 | t.root->left_child->print(os, ""); 849 | return os; 850 | } 851 | #endif 852 | 853 | } 854 | --------------------------------------------------------------------------------