├── README.md ├── CMakeLists.txt ├── .gitignore ├── LICENSE ├── test.cpp └── src ├── node23.hpp └── heap23.hpp /README.md: -------------------------------------------------------------------------------- 1 | 2-3 Heap 2 | ======== 3 | 4 | Implementation 2-3 heap on C++ (Standard 2011 - ISO/IEC 14882:2011) 5 | 6 | Based on article : http://www.cosc.canterbury.ac.nz/tad.takaoka/2-3heaps.pdf 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.4) 2 | project(23heap) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 5 | 6 | set(23HEAP_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src) 7 | set(SOURCE_FILES test.cpp) 8 | 9 | include_directories( 10 | ${CMAKE_CURRENT_SOURCE_DIR} 11 | ${CMAKE_BINARY_DIR} 12 | ${23HEAP_INCLUDE_DIR} 13 | ) 14 | 15 | add_executable(23heap_test ${SOURCE_FILES}) 16 | 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Directory-based JetBrain project format: 31 | .idea/ 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Vladislav Orlov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | 3 | #include 4 | #include "deps/catch.hpp" 5 | 6 | using namespace std; 7 | 8 | TEST_CASE("Inserting changes isEmpty", "[23heap]") 9 | { 10 | Heap23 a; 11 | 12 | REQUIRE(a.isEmpty()); 13 | a.insert(24, "002"); // 2 14 | REQUIRE_FALSE(a.isEmpty()); 15 | } 16 | 17 | TEST_CASE("Can use other types", "[23heap]") 18 | { 19 | Heap23 a; 20 | 21 | Heap23 intHeap; 22 | intHeap.insert(20, 15); 23 | Node23 *intNode = intHeap.extractMin(); 24 | REQUIRE(intNode->priority() == 20); 25 | REQUIRE(intNode->value() == 15); 26 | 27 | Heap23 doubleHeap; 28 | doubleHeap.insert(-12, 15.12375); 29 | Node23 *doubleNode = doubleHeap.extractMin(); 30 | REQUIRE(doubleNode->priority() == -12); 31 | REQUIRE(doubleNode->value() == 15.12375); 32 | 33 | Heap23> setHeap; 34 | setHeap.insert(3, std::set({4, 8, 9, 2})); 35 | Node23> *setNode = setHeap.extractMin(); 36 | REQUIRE(setNode->priority() == 3); 37 | REQUIRE(setNode->value() == std::set({4, 8, 9, 2})); 38 | } 39 | 40 | TEST_CASE("Extracting in priority", "[23heap]") 41 | { 42 | Heap23 a; 43 | 44 | REQUIRE(a.isEmpty()); 45 | auto ptr1 = a.insert(24, "002"); // 2 46 | auto ptr2 = a.insert(18, "001"); // 1 47 | auto ptr3 = a.insert(52, "010"); // 10 48 | auto ptr4 = a.insert(38, "006"); // 6 49 | auto ptr5 = a.insert(30, "004"); // 4 50 | auto ptr6 = a.insert(26, "003"); // 3 51 | auto ptr7 = a.insert(46, "009"); // 9 52 | auto ptr8 = a.insert(39, "007"); // 7 53 | auto ptr9 = a.insert(41, "008"); // 8 54 | auto ptr0 = a.insert(35, "005"); // 5 55 | REQUIRE_FALSE(a.isEmpty()); 56 | REQUIRE(a.extractMin() == ptr2); 57 | REQUIRE(a.extractMin() == ptr1); 58 | REQUIRE(a.extractMin() == ptr6); 59 | REQUIRE(a.extractMin() == ptr5); 60 | REQUIRE(a.extractMin() == ptr0); 61 | REQUIRE(a.extractMin() == ptr4); 62 | REQUIRE(a.extractMin() == ptr8); 63 | REQUIRE(a.extractMin() == ptr9); 64 | REQUIRE(a.extractMin() == ptr7); 65 | REQUIRE(a.extractMin() == ptr3); 66 | REQUIRE(a.isEmpty()); 67 | } 68 | 69 | TEST_CASE("Merge two heaps", "[23heap]") 70 | { 71 | Heap23 a; 72 | Heap23 b; 73 | 74 | REQUIRE(a.isEmpty()); 75 | REQUIRE(b.isEmpty()); 76 | auto ptr1 = a.insert(24, "002"); 77 | auto ptr2 = a.insert(18, "001"); 78 | auto ptr3 = a.insert(52, "006"); 79 | auto ptr4 = b.insert(30, "004"); 80 | auto ptr5 = b.insert(26, "003"); 81 | auto ptr6 = b.insert(46, "005"); 82 | REQUIRE_FALSE(a.isEmpty()); 83 | REQUIRE_FALSE(b.isEmpty()); 84 | REQUIRE(a.min() == ptr2); 85 | REQUIRE(b.min() == ptr5); 86 | a.merge(b); 87 | REQUIRE(b.isEmpty()); 88 | REQUIRE_FALSE(a.isEmpty()); 89 | REQUIRE(a.extractMin() == ptr2); 90 | REQUIRE(a.extractMin() == ptr1); 91 | REQUIRE(a.extractMin() == ptr5); 92 | REQUIRE(a.extractMin() == ptr4); 93 | REQUIRE(a.extractMin() == ptr6); 94 | REQUIRE(a.extractMin() == ptr3); 95 | REQUIRE(a.isEmpty()); 96 | } 97 | 98 | TEST_CASE("Decrease key of node in heap", "[23heap]") 99 | { 100 | Heap23 a; 101 | 102 | auto ptr1 = a.insert(24, "002"); 103 | auto ptr2 = a.insert(18, "001"); 104 | auto ptr3 = a.insert(52, "010"); 105 | auto ptr4 = a.insert(38, "006"); 106 | REQUIRE(a.min() == ptr2); 107 | a.decreaseKey(ptr1, 14); 108 | REQUIRE(a.min() == ptr1); 109 | } 110 | -------------------------------------------------------------------------------- /src/node23.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NODE_23_HPP 3 | #define NODE_23_HPP 4 | 5 | #include 6 | 7 | template 8 | class Node23 9 | { 10 | template friend class Heap23; 11 | template friend int merge_nodes(Node23 **a, Node23 **b); 12 | 13 | public: 14 | Node23(int key, T value) : 15 | child(NULL), 16 | left(NULL), 17 | right(NULL), 18 | parent(NULL), 19 | partner(NULL), 20 | extra(false), 21 | dim(0), 22 | key_(key), 23 | value_(value) 24 | { 25 | } 26 | 27 | int priority() { return key_; } 28 | T value() { return value_; } 29 | 30 | void addChild(Node23 *node); 31 | void removeChild(Node23 *child); 32 | void replaceChild(Node23 *new_node); 33 | 34 | void print(std::ostream &out, unsigned level); 35 | 36 | protected: 37 | void printPartners(std::ostream &out, unsigned level); 38 | 39 | private: 40 | Node23 *parent; 41 | Node23 *child; 42 | Node23 *left; 43 | Node23 *right; 44 | Node23 *partner; 45 | 46 | bool extra; 47 | int dim; 48 | int key_; 49 | T value_; 50 | }; 51 | 52 | template 53 | int merge_nodes(Node23 **a, Node23 **b) 54 | { 55 | Node23 *tree, *next_tree, *other, *next_other; 56 | int c = 0; 57 | 58 | if ((*a)->priority() <= (*b)->priority()) { 59 | tree = (*a); 60 | other = (*b); 61 | } else { 62 | tree = (*b); 63 | other = (*a); 64 | } 65 | ++c; 66 | 67 | next_tree = tree->partner; 68 | next_other = other->partner; 69 | 70 | if (!next_tree) { 71 | if (next_other) { 72 | tree->addChild(other); 73 | tree->dim++; 74 | *a = NULL; 75 | *b = tree; 76 | } else { 77 | tree->partner = other; 78 | other->partner = tree; 79 | other->extra = true; 80 | 81 | *a = tree; 82 | *b = NULL; 83 | } 84 | } else if (!next_other) { 85 | tree->partner = NULL; 86 | other->partner = next_tree; 87 | next_tree->partner = other; 88 | 89 | if (other->priority() < next_tree->priority()) { 90 | tree->addChild(other); 91 | } else { 92 | next_tree->extra = false; 93 | other->extra = true; 94 | tree->addChild(next_tree); 95 | } 96 | 97 | ++(tree->dim); 98 | 99 | ++c; 100 | *a = NULL; 101 | *b = tree; 102 | } else { 103 | tree->partner = NULL; 104 | next_tree->partner = NULL; 105 | next_tree->extra = false; 106 | next_tree->left = next_tree->right = next_tree; 107 | next_tree->parent = NULL; 108 | 109 | tree->addChild(other); 110 | ++(tree->dim); 111 | 112 | *a = next_tree; 113 | *b = tree; 114 | } 115 | return c; 116 | } 117 | 118 | template 119 | void Node23::addChild(Node23 *node) 120 | { 121 | Node23 *left, *right; 122 | if ((left = child)) { 123 | right = left->right; 124 | node->left = left; 125 | node->right = right; 126 | right->left = node; 127 | left->right = node; 128 | } else { 129 | node->left = node->right = node; 130 | } 131 | child = node; 132 | node->parent = this; 133 | } 134 | 135 | template 136 | void Node23::removeChild(Node23 *node) 137 | { 138 | Node23 *left, *right; 139 | if (node->dim) { 140 | left = node->left; 141 | right = node->right; 142 | left->right = right; 143 | right->left = left; 144 | child = left; 145 | } else { 146 | child = NULL; 147 | } 148 | } 149 | 150 | template 151 | void Node23::replaceChild(Node23 *new_node) 152 | { 153 | Node23 *l, *r = right; 154 | 155 | if (r == this) { 156 | new_node->right = new_node->left = new_node; 157 | } else { 158 | l = left; 159 | l->right = new_node; 160 | r->left = new_node; 161 | new_node->left = l; 162 | new_node->right = r; 163 | } 164 | 165 | new_node->parent = parent; 166 | if (parent->child == this) 167 | parent->child = new_node; 168 | } 169 | 170 | template 171 | void Node23::print(std::ostream &out, unsigned level) 172 | { 173 | Node23 *x; 174 | bool is_started = false; 175 | for (x = this; !is_started || x != this; x = x->right) { 176 | if (!is_started) 177 | is_started = true; 178 | for (int i = 0; i < level; ++i) { 179 | out << " "; 180 | } 181 | out << x->key_ << '[' << x->dim << ']' << '[' << x->extra << ']'; 182 | if (x->partner != NULL && x->partner != x) { 183 | out << " | " << x->partner->key_ << '[' << x->partner->dim << ']' << '[' << x->partner->extra << ']'; 184 | } 185 | out << std::endl; 186 | if (x->child != NULL) { 187 | x->child->print(out, level + 1); 188 | } 189 | if (x->partner != NULL && x->partner != x && x->partner->child != NULL) { 190 | x->partner->child->print(out, level + 1); 191 | } 192 | } 193 | } 194 | 195 | template 196 | void Node23::printPartners(std::ostream &out, unsigned level) 197 | { 198 | Node23 *x = partner; 199 | for (int i = 0; i < level; ++i) { 200 | out << " "; 201 | } 202 | out << x->key_ << '[' << x->dim << ']' << '[' << x->extra << ']' << std::endl; 203 | if (x->child != NULL) { 204 | x->child->print(out, level + 1); 205 | } 206 | } 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /src/heap23.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef HEAP_23_HPP 3 | #define HEAP_23_HPP 4 | 5 | #include 6 | #include 7 | #include "node23.hpp" 8 | 9 | template 10 | class Heap23 11 | { 12 | public: 13 | Heap23(int max_nodes = 100); 14 | ~Heap23(); 15 | 16 | Node23 *insert(int key, T value); 17 | Node23 *min(); 18 | Node23 *extractMin(); 19 | bool merge(Heap23 &heap); 20 | void remove(Node23 *node); 21 | void decreaseKey(Node23 *node, int new_key); 22 | void print(std::ostream &out); 23 | bool isEmpty(); 24 | 25 | protected: 26 | void meld(Node23 *list); 27 | 28 | private: 29 | Node23 **trees; 30 | int max_trees_; 31 | int nnodes; 32 | int value; 33 | }; 34 | 35 | // PUBLIC FUNCTIONS 36 | // ============================================================================ 37 | 38 | template 39 | Heap23::Heap23(int max_nodes) 40 | : nnodes(0), value(0) 41 | { 42 | max_trees_ = (int) (0.5 + std::log(max_nodes + 1) / std::log(2.0)); 43 | trees = new Node23 *[max_trees_]; 44 | 45 | for (int i = 0; i < max_trees_; ++i) { 46 | trees[i] = NULL; 47 | } 48 | } 49 | 50 | template 51 | Heap23::~Heap23() 52 | { 53 | delete[] trees; 54 | } 55 | 56 | template 57 | Node23 *Heap23::insert(int key, T value) 58 | { 59 | Node23 *node = new Node23(key, value); 60 | meld(node); 61 | ++nnodes; 62 | return node; 63 | } 64 | 65 | 66 | template 67 | Node23 *Heap23::min() 68 | { 69 | Node23 *min_node, *next; 70 | long k, k2; 71 | int r, v; 72 | 73 | v = value; 74 | r = -1; 75 | while (v) { 76 | v = v >> 1; 77 | r++; 78 | } 79 | 80 | min_node = trees[r]; 81 | k = min_node->priority(); 82 | while (r > 0) { 83 | r--; 84 | next = trees[r]; 85 | if (next) { 86 | if ((k2 = next->priority()) < k) { 87 | k = k2; 88 | min_node = next; 89 | } 90 | } 91 | } 92 | return min_node; 93 | } 94 | 95 | 96 | template 97 | Node23 *Heap23::extractMin() 98 | { 99 | Node23 *child, *next, *partner, *min_node = min(); 100 | 101 | int r = min_node->dim; 102 | if ((partner = min_node->partner)) { 103 | partner->partner = NULL; 104 | partner->extra = false; 105 | partner->parent = NULL; 106 | partner->left = partner->right = partner; 107 | trees[r] = partner; 108 | } else { 109 | trees[r] = NULL; 110 | value -= (1 << r); 111 | } 112 | --nnodes; 113 | 114 | child = min_node->child; 115 | if (child) { 116 | next = child->right; 117 | next->left = child->right = NULL; 118 | meld(next); 119 | } 120 | 121 | return min_node; 122 | } 123 | 124 | 125 | template 126 | bool Heap23::merge(Heap23 &heap) 127 | { 128 | for (int i = 0; i < heap.max_trees_; ++i) { 129 | if (heap.trees[i] != NULL) { 130 | heap.trees[i]->right = heap.trees[i]->left = NULL; 131 | meld(heap.trees[i]); 132 | heap.trees[i] = NULL; 133 | } 134 | } 135 | nnodes += heap.nnodes; 136 | heap.nnodes = 0; 137 | return true; 138 | } 139 | 140 | template 141 | void Heap23::remove(Node23 *node) 142 | { 143 | Node23 *p, *m, *ax, *bx, *ap, *bp, *b1, *a1, *a2, *l, *r, *partner = node->partner; 144 | int d; 145 | 146 | if (node->extra) { 147 | node->partner->partner = NULL; 148 | node->partner = NULL; 149 | node->extra = false; 150 | } else if (partner) { 151 | partner->partner = NULL; 152 | node->partner = NULL; 153 | partner->extra = false; 154 | 155 | node->replaceChild(partner); 156 | } else { 157 | m = node->right; 158 | if (m->dim) { 159 | ax = ap = NULL; 160 | bx = m->child->partner; 161 | bp = (Node23 *) (bx ? NULL : m->child); 162 | } else { 163 | m = node->parent; 164 | if (m->extra) { 165 | bx = bp = NULL; 166 | m = m->partner; 167 | ax = m->child->partner; 168 | ap = (Node23 *) (ax ? NULL : m->child); 169 | } else { 170 | if (m->parent) { 171 | ax = m->left->partner; 172 | ap = (Node23 *) (ax ? NULL : m->left); 173 | } else { 174 | ax = ap = NULL; 175 | } 176 | 177 | if ((m = m->partner)) { 178 | bx = m->child->partner; 179 | bp = (Node23 *) (bx ? NULL : m->child); 180 | } else { 181 | bx = bp = NULL; 182 | } 183 | } 184 | } 185 | 186 | if (bx) { 187 | bx->partner->partner = NULL; 188 | bx->partner = NULL; 189 | bx->extra = false; 190 | 191 | node->replaceChild(bx); 192 | } else if (bp) { 193 | b1 = bp->parent; 194 | 195 | remove(b1); 196 | b1->removeChild(bp); 197 | bp->partner = b1; 198 | b1->partner = bp; 199 | bp->extra = true; 200 | b1->dim = node->dim; 201 | 202 | node->replaceChild(b1); 203 | } else if (ax) { 204 | p = node->parent; 205 | a2 = ax->partner; 206 | a1 = a2->parent; 207 | 208 | p->removeChild(node); 209 | 210 | ax->partner = NULL; 211 | ax->extra = false; 212 | 213 | d = a2->dim; 214 | a2->dim = p->dim; 215 | p->dim = d; 216 | 217 | a2->addChild(ax); 218 | 219 | if (p->extra) { 220 | p->partner = NULL; 221 | p->extra = false; 222 | 223 | a2->partner = a1; 224 | a1->partner = a2; 225 | a2->extra = true; 226 | 227 | a2->replaceChild(p); 228 | } else { 229 | a2->partner = NULL; 230 | if ((l = a2->left) != p) { 231 | r = p->right; 232 | p->left = l; 233 | a2->right = r; 234 | p->right = a2; 235 | a2->left = p; 236 | l->right = p; 237 | r->left = a2; 238 | 239 | if (a1->child == p) { 240 | a1->child = a2; 241 | } 242 | } else { 243 | a1->child = a2; 244 | } 245 | } 246 | } else if (ap) { 247 | p = node->parent; 248 | p->removeChild(node); 249 | remove(p); 250 | p->dim = node->dim; 251 | 252 | p->partner = ap; 253 | ap->partner = p; 254 | 255 | if (p->priority() < ap->priority()) { 256 | p->extra = false; 257 | ap->replaceChild(p); 258 | ap->extra = true; 259 | } else { 260 | p->extra = true; 261 | } 262 | } else { 263 | d = node->dim; 264 | p = node->parent; 265 | 266 | p->removeChild(node); 267 | 268 | trees[d + 1] = NULL; 269 | value -= (1 << (d + 1)); 270 | p->dim = d; 271 | 272 | p->left = p->right = NULL; 273 | meld(p); 274 | } 275 | } 276 | } 277 | 278 | template 279 | void Heap23::decreaseKey(Node23 *node, int new_key) 280 | { 281 | node->key_ = new_key; 282 | 283 | if (!(node->parent || node->extra)) { 284 | return; 285 | } 286 | 287 | remove(node); 288 | node->right = node->left = NULL; 289 | 290 | meld(node); 291 | } 292 | 293 | template 294 | void Heap23::print(std::ostream &out) 295 | { 296 | for (int i = 0; i < max_trees_; ++i) { 297 | if (trees[i] != NULL) { 298 | out << "Tree #" << i << std::endl; 299 | trees[i]->print(out, 0); 300 | } 301 | } 302 | } 303 | 304 | template 305 | bool Heap23::isEmpty() 306 | { 307 | return nnodes == 0; 308 | } 309 | 310 | // PROTECTED FUNCTIONS 311 | // ============================================================================ 312 | 313 | template 314 | void Heap23::meld(Node23 *list) 315 | { 316 | Node23 *next, *add_tree, *carry_tree; 317 | int d; 318 | 319 | add_tree = list; 320 | carry_tree = NULL; 321 | 322 | do { 323 | if (add_tree) { 324 | next = add_tree->right; 325 | add_tree->right = add_tree->left = add_tree; 326 | add_tree->parent = NULL; 327 | } else { 328 | add_tree = carry_tree; 329 | carry_tree = NULL; 330 | } 331 | 332 | if (carry_tree) { 333 | merge_nodes(&add_tree, &carry_tree); 334 | } 335 | 336 | if (add_tree) { 337 | d = add_tree->dim; 338 | if (trees[d]) { 339 | merge_nodes(&trees[d], &add_tree); 340 | if (!trees[d]) value -= (1 << d); 341 | carry_tree = add_tree; 342 | } else { 343 | trees[d] = add_tree; 344 | value += (1 << d); 345 | } 346 | } 347 | 348 | add_tree = next; 349 | } while (add_tree || carry_tree); 350 | } 351 | 352 | #endif 353 | --------------------------------------------------------------------------------