source: branches/kendall-score/yat/utility/ranking/Impl.cc @ 4075

Last change on this file since 4075 was 4075, checked in by Peter, 19 months ago

fix some docs and get rid of function not used. refs #710

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.0 KB
Line 
1// $Id: Impl.cc 4075 2021-08-20 06:54:37Z peter $
2
3/*
4  Copyright (C) 2021 Peter Johansson
5
6  This file is part of the yat library, http://dev.thep.lu.se/yat
7
8  The yat library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 3 of the
11  License, or (at your option) any later version.
12
13  The yat library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with yat. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include <config.h>
23
24#include "Ranking.h"
25
26#include <cassert>
27#include <cstddef>
28#include <iostream>
29
30namespace theplu {
31namespace yat {
32namespace utility {
33namespace ranking {
34
35  Impl::Impl(void)
36  {
37    reset();
38  }
39
40
41  Impl::Impl(Impl&& from)
42  {
43    reset();
44    move_data(std::move(from));
45  }
46
47
48  Impl& Impl::operator=(Impl&& rhs)
49  {
50    assert(!head_.parent_);
51    move_data(std::move(rhs));
52    assert(validate());
53    return *this;
54  }
55
56
57  bool Impl::empty(void) const
58  {
59    return !root_node();
60  }
61
62
63  size_t Impl::size(void) const
64  {
65    assert(head_.size_ > 0);
66    return head_.size_ - 1;
67  }
68
69
70  void Impl::move_data(Impl&& from)
71  {
72    assert(empty());
73
74    head_.parent_ = from.head_.parent_;
75    head_.left_ = from.head_.left_;
76    if (head_.left_) {
77      head_.left_->parent_ = &head_;
78      head_.right_ = from.head_.right_;
79    }
80    else
81      head_.right_ = &head_;
82    head_.height_ = from.head_.height_;
83    head_.size_ = from.head_.size_;
84    from.reset();
85    assert(validate());
86  }
87
88
89  void Impl::relink(const NodeBase* node, NodeBase* child)
90  {
91    assert(node->parent_);
92    assert(node != &head_);
93    assert(child != &head_);
94
95    // make child the child of node's parent
96    if (node->is_left_node())
97      node->parent_->left_ = child;
98    else if (node->is_right_node())
99      node->parent_->right_ = child;
100
101    // make node's parent the parent of child
102    if (child)
103      child->parent_ = node->parent_;
104
105    // inherit the kids
106    if (child) {
107      if (node->left_ && node->left_!=child) {
108        assert(!child->left_);
109        child->left_ = node->left_;
110        if (node->left_)
111          node->left_->parent_ = child;
112      }
113      if (node->right_ && node->right_!=child) {
114        assert(!child->right_);
115        child->right_ = node->right_;
116        if (node->right_)
117          node->right_->parent_ = child;
118      }
119    }
120
121    // update pointer to left_most node
122    if (head_.left_ == node) {
123      head_.left_ = child ? child : node->parent_;
124    }
125    assert(child==nullptr || child->is_left_node() || child->is_right_node());
126  }
127
128
129  size_t Impl::ranking(const NodeBase* node) const
130  {
131    assert(node);
132    if (node->is_head_node())
133      return size();
134
135    assert(node->parent_);
136    // The rank of the parent is the sum of the rank of the
137    // left->child, the child itself, and the size of the child's
138    // right branch.
139    if (node->is_left_node())
140      return ranking(node->parent_) - (1 + ranking::size(node->right_));
141
142    // right node
143    return ranking(node->parent_) + 1 + ranking::size(node->left_);
144  }
145
146
147  void Impl::reset(void)
148  {
149    head_.parent_ = nullptr;
150    head_.left_ = nullptr;
151    head_.right_ = &head_; // most left node
152    head_.update_height();
153    head_.update_size();
154    assert(validate());
155  }
156
157
158  void Impl::erase_and_rebalance(const NodeBase* node)
159  {
160    // two children
161    if (node->left_ && node->right_) {
162      // When node has two branches, we take the most leftmost node in
163      // the right branch and place in nodes place.
164      ranking::NodeBase* leftmost = node->right_->left_most();
165      assert(leftmost->left_ == nullptr);
166
167      // If the leftmost node has a kid, we need to relink the kid
168      // with its grand parent
169      if (leftmost->parent_ != node)
170        relink(leftmost, leftmost->right_);
171      relink(node, leftmost);
172      assert(leftmost->left_ == node->left_);
173      assert(!leftmost->left_ || leftmost->left_->parent_==leftmost);
174      leftmost->update_height();
175      leftmost->parent_->update_height_recursively();
176      leftmost->update_size();
177      leftmost->parent_->decrement_size();
178      erase_rebalance(leftmost);
179    }
180    else {
181      // single child node is simple, the child takes the node's place
182      relink(node, node->left_ ? node->left_ : node->right_);
183      node->parent_->decrement_size();
184      node->parent_->update_height_recursively();
185      erase_rebalance(node->parent_);
186    }
187  }
188
189
190  void Impl::insert_and_rebalance(std::unique_ptr<NodeBase>&& element,
191                                  NodeBase& parent, NodeBase*& child)
192  {
193    assert(child == nullptr);
194    child = element.release();
195    child->parent_ = &parent;
196    parent.increment_size();
197    parent.update_height_recursively();
198
199    insert_rebalance(&parent, child);
200  }
201
202
203  void Impl::erase_rebalance(NodeBase* node)
204  {
205    assert(node);
206    if (node->is_root_node())
207      return;
208
209    int balance = node->balance();
210
211    if (std::abs(balance) > 1) {
212      assert(0);
213    }
214
215    NodeBase* parent = node->parent_;
216    assert(parent);
217    erase_rebalance(parent);
218  }
219
220
221  void Impl::insert_rebalance(NodeBase* node, NodeBase* child)
222  {
223    assert(node);
224    assert(child);
225    assert(child->parent_ == node);
226    assert(child == node->left_ || child == node->right_);
227
228    NodeBase* parent = node->parent_;
229    assert(parent);
230    if (parent->is_head_node())
231      return;
232
233    // left height minus right height
234    int balance = parent->balance();
235
236    /*
237      If parent is unbalanced, we have four cases.
238
239      Below parent is denoted z
240      node is denoted y
241      child is denoted x
242
243      and all three are ancestors of the just inserted node.
244
245      a) Left Left Case
246
247      T1, T2, T3 and T4 are subtrees.
248            z                                      y
249           / \                                   /   \
250          y   T4      Right Rotate (z)          x      z
251         / \          - - - - - - - - ->      /  \    /  \
252        x   T3                               T1  T2  T3  T4
253       / \
254      T1  T2
255
256      b) Left Right Case
257
258            z                              z                           x
259           / \                            / \                        /   \
260          y   T4  Left Rotate (y)        x   T4  Right Rotate(z)    y     z
261         / \      - - - - - - - - ->    / \     - - - - - - - ->   / \   / \
262        T1  x                          y   T3                     T1 T2 T3 T4
263           / \                        / \
264          T2 T3                     T1   T2
265
266      c) Right Right Case
267
268          z                              y
269         / \                            /  \
270        T1  y     Left Rotate(z)       z    x
271           / \    - - - - - - - ->    / \  / \
272          T2  x                      T1 T2T3 T4
273             / \
274            T3 T4
275
276      d) Right Left Case
277
278        z                            z                            x
279       / \                          / \                         /   \
280      T1  y   Right Rotate (y)    T1   x    Left Rotate(z)     z     y
281         / \  - - - - - - - - ->      / \   - - - - - - - ->  / \   / \
282        x   T4                      T2   y                  T1  T2 T3  T4
283       / \                              / \
284      T2  T3                           T3  T4
285    */
286
287    if (balance < -1) {
288      assert(height(parent->right_) > height(parent->left_));
289      assert(parent->right_ == node);
290      // right right case
291      if (node->right_ == child) {
292        left_rotate(parent);
293        return;
294      }
295      // right left case
296      assert(node->left_ == child);
297      right_rotate(node);
298      left_rotate(parent);
299      return;
300    }
301    else if (balance > 1) {
302      // left right case
303      if (node->right_ == child) {
304        left_rotate(node);
305        right_rotate(parent);
306        return;
307      }
308      // left left case
309      assert(node->left_ == child);
310      right_rotate(parent);
311      return;
312    }
313
314    assert(parent->parent_);
315    insert_rebalance(parent, node);
316  }
317
318
319  NodeBase* Impl::left_rotate(NodeBase* x)
320  {
321    assert(x);
322    NodeBase* y = x->right_;
323    assert(y);
324    NodeBase* T2 = y->left_;
325
326    // rotate
327    if (x->is_left_node())
328      x->parent_->left_ = y;
329    else {
330      assert(x->is_right_node());
331      x->parent_->right_ = y;
332    }
333    y->parent_ = x->parent_;
334
335    y->left_ = x;
336    x->parent_ = y;
337
338    x->right_ = T2;
339    if (T2)
340      T2->parent_ = x;
341
342    // update height - always update from leaf and to root
343    x->update_height();
344    y->update_height();
345    assert(y->parent_);
346    y->parent_->update_height_recursively();
347
348    // update size
349    x->update_size();
350    y->update_size();
351
352    return y;
353  }
354
355
356  NodeBase* Impl::right_rotate(NodeBase* y)
357  {
358    NodeBase* x = y->left_;
359    assert(x);
360    NodeBase* T2 = x->right_;
361
362    // rotate
363    if (y->is_left_node())
364      y->parent_->left_ = x;
365    else {
366      assert(y->is_right_node());
367      y->parent_->right_ = x;
368    }
369    x->parent_ = y->parent_;
370
371    x->right_ = y;
372    y->parent_ = x;
373
374    y->left_ = T2;
375    if (T2)
376      T2->parent_ = y;
377
378    // update height
379    y->update_height();
380    x->update_height();
381    assert(x->parent_);
382    x->parent_->update_height_recursively();
383
384    // update size
385    y->update_size();
386    x->update_size();
387
388    return x;
389  }
390
391
392  bool Impl::validate(void) const
393  {
394#ifdef NDEBUG
395    return true;
396#else
397    if (!head_.validate(true)) {
398      std::cerr << "Impl: head failed\n";
399      return false;
400    }
401    assert(left_most() == head_.left_most());
402
403    if (root_node()) {
404      if (root_node()->is_left_node() == false) {
405        std::cerr << "error: root is not a left node\n";
406        return false;
407      }
408      if (root_node()->is_right_node()) {
409        std::cerr << "error: root is a right node\n";
410        return false;
411      }
412    }
413
414    if (!validate(root_node())) {
415      std::cerr << "Impl: validate(root_node()) failed\n";
416      return false;
417    }
418
419
420    /*
421    if (root_node()) {
422      if (root_node()->left_most() != head_.right_) {
423        std::cerr << "head_.right incorrect\n";
424        return false;
425      }
426      if (!root_node()->recursive_validate())
427        return false;
428    }
429    else if (!head_.validate())
430      return false;
431    */
432    return true;
433#endif
434  }
435
436
437  bool Impl::validate(const NodeBase* node) const
438  {
439    if (node == nullptr)
440      return true;
441    node->validate();
442    validate(node->left_);
443    validate(node->right_);
444    return true;
445  }
446
447
448  NodeBase*& Impl::left_most(void)
449  {
450    return head_.right_;
451  }
452
453
454  const NodeBase* Impl::left_most(void) const
455  {
456    return head_.right_;
457  }
458
459
460  NodeBase*& Impl::root_node(void)
461  {
462    return head_.left_;
463  }
464
465
466  const NodeBase* Impl::root_node(void) const
467  {
468    return head_.left_;
469  }
470
471
472}
473}}} // of namespace utility, yat, and theplu
Note: See TracBrowser for help on using the repository browser.