source: branches/kendall-score/yat/utility/Ranking.h @ 4071

Last change on this file since 4071 was 4071, checked in by Peter, 20 months ago

Add variables height_ and size_ in NodeBase?, which describes the longest distance to its leaves and the size of the subtree in which it is the root, respectively. Use these variables to calculate the ranking, which means the ranking now scales like the height rather than the number of nodes. refs #710

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.5 KB
Line 
1#ifndef theplu_yat_utility_ranking
2#define theplu_yat_utility_ranking
3
4// $Id: Ranking.h 4071 2021-08-18 02:31:29Z peter $
5
6/*
7  Copyright (C) 2021 Peter Johansson
8
9  This file is part of the yat library, http://dev.thep.lu.se/yat
10
11  The yat library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 3 of the
14  License, or (at your option) any later version.
15
16  The yat library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20
21  You should have received a copy of the GNU General Public License
22  along with yat. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "ranking/Impl.h"
26#include "ranking/Iterator.h"
27#include "ranking/NodeBase.h"
28#include "ranking/NodeValue.h"
29
30#include "yat_assert.h"
31
32#include <cstddef>
33#include <functional>
34#include <memory>
35
36#include <iostream> // debug
37namespace theplu {
38namespace yat {
39namespace utility {
40
41  /**
42     Class is a binary tree with the special extension that it allow
43     fast access to the rank of an element in the tree.
44
45     \since New in yat 0.19
46   */
47  template<typename T, class Compare = std::less<T> >
48  class Ranking
49  {
50  public:
51    /// value type
52    typedef T value_type;
53    /// type used to compare elements
54    typedef Compare key_compare;
55    /// size type
56    typedef size_t size_type;
57    /// iterator
58    typedef ranking::Iterator<T> iterator;
59    /// iterator
60    typedef ranking::Iterator<T> const_iterator;
61    /// reverse iterator
62    typedef std::reverse_iterator<iterator> reverse_iterator;
63    /// reverse iterator
64    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
65
66    /**
67       \brief Default constructor
68     */
69    Ranking(void) = default;
70
71    /**
72       Construct empty container with comparison function \c c.
73     */
74    Ranking(const Compare& c)
75      : compare_(c)
76    {
77      YAT_ASSERT(validate());
78    }
79
80
81    /**
82       \brief Copy constructor
83     */
84    Ranking(const Ranking& other);
85
86    /**
87       \brief move constructor
88     */
89    Ranking(Ranking&& other);
90
91    /**
92       \brief assignment operator
93     */
94    Ranking& operator=(const Ranking& other);
95
96    /**
97       \brief move assignment
98     */
99    Ranking& operator=(Ranking&& other);
100
101
102    /**
103       \return iterator pointing to the first element
104     */
105    iterator begin(void)
106    {
107      return iterator(left_most());
108    }
109
110
111    /**
112       \return iterator pointing to the first element
113     */
114    const_iterator begin(void) const
115    {
116      return cbegin();
117    }
118
119
120    /**
121       \return iterator pointing to the first element
122     */
123    const_iterator cbegin(void) const
124    {
125      return const_iterator(left_most());
126    }
127
128
129    /**
130       \return iterator pointing to one-passed-last element
131     */
132    iterator end(void)
133    {
134      return iterator(&impl_.head_);
135    }
136
137
138    /**
139       \return iterator pointing to one-passed-last element
140     */
141    const_iterator end(void) const
142    {
143      return cend();
144    }
145
146
147    /**
148       \return iterator pointing to one-passed-last element
149     */
150    const_iterator cend(void) const
151    {
152      return const_iterator(&impl_.head_);
153    }
154
155
156    /**
157       \return reverse iterator pointing to first element
158     */
159    reverse_iterator rbegin(void)
160    {
161      return reverse_iterator(end());
162    }
163
164
165    /**
166       \return reverse iterator pointing to one-passed-last element
167     */
168    reverse_iterator rend(void)
169    {
170      return reverse_iterator(begin());
171    }
172
173
174    /**
175       \return reverse iterator pointing to one-passed-last element
176     */
177    const_reverse_iterator rend(void) const
178    {
179      return crend();
180    }
181
182
183    /**
184       \return reverse iterator pointing to first element
185     */
186    const_reverse_iterator rbegin(void) const
187    {
188      return crbegin();
189    }
190
191
192    /**
193       \return reverse iterator pointing to first element
194     */
195    const_reverse_iterator crbegin(void) const
196    {
197      return const_reverse_iterator(cend());
198    }
199
200    /**
201       \return reverse iterator pointing to the one-passed-last element
202     */
203    const_reverse_iterator crend(void) const
204    {
205      return const_reverse_iterator(cbegin());
206    }
207
208
209    /**
210       Remove all nodes
211     */
212    void clear(void)
213    {
214      if (size()) {
215        YAT_ASSERT(first_node() != &impl_.head_);
216        erase(first_node());
217      }
218      impl_.reset();
219    }
220
221
222    /**
223       access comparison function which is used to sort elements
224     */
225    const Compare& compare(void) const
226    {
227      return compare_;
228    }
229
230
231    /**
232       \return true if (and only if) container has zero elements
233     */
234    bool empty(void) const
235    {
236      return root_node() == nullptr;
237    }
238
239
240    /**
241       Remove element pointed to by \c position.
242
243       \return An iterator pointing to the element that follows the
244       last element removed.
245     */
246    iterator erase(const_iterator position);
247
248    /**
249       Erase all elements that are equivalent with \c value
250       \return number of elements removed
251     */
252    size_type erase(const T& value);
253
254    /**
255       Remove elements in range [first, last).
256
257       \return An iterator pointing to the element that follows the
258       last element removed.
259     */
260    iterator erase(const_iterator first, const_iterator last);
261
262    /**
263       Find an element that is equivalent to x
264     */
265    const_iterator find(const T& x) const;
266
267
268    /**
269       \brief insert an element
270     */
271    iterator insert(const T& element)
272    {
273      std::unique_ptr<ranking::NodeValue<T>>
274        newnode(new ranking::NodeValue<T>(element));
275      return insert(std::move(newnode));
276    }
277
278
279    /**
280       \brief insert an element
281     */
282    iterator insert(T&& element)
283    {
284      std::unique_ptr<ranking::NodeValue<T>>
285        newnode(new ranking::NodeValue<T>(std::move(element)));
286      return insert(std::move(newnode));
287    }
288
289
290    /**
291       \brief insert with hint
292     */
293    iterator insert(const_iterator hint, const T& element)
294    {
295      // FIXME use the hint
296      return insert(element);
297    }
298
299
300    /**
301       \brief insert with hint
302     */
303    iterator insert(const_iterator hint,  T&& element)
304    {
305      // FIXME use the hint
306      return insert(std::move(element));
307    }
308
309
310    /**
311       \brief insert range
312     */
313    template<typename InputIterator>
314    void insert(InputIterator first, InputIterator last)
315    {
316      for (; first!=last; ++first)
317        insert(end(), *first);
318    }
319
320
321    /**
322       \return the first element which is equal (or greater) to \c x
323     */
324    const_iterator lower_bound(const T& x) const
325    {
326      if (empty())
327        return cend();
328      return lower_bound(first_node(), last_node(), x);
329    }
330
331
332    /**
333       \return the first element which is greater than \c x
334     */
335    const_iterator upper_bound(const T& x) const
336    {
337      if (empty())
338        return cend();
339      return upper_bound(first_node(), last_node(), x);
340    }
341
342
343    /**
344       \return number of elements smaller than \c it
345     */
346    size_t ranking(const_iterator it) const
347    {
348      return impl_.ranking(it.node_);
349    }
350
351
352    /**
353       \return number of elements in container
354     */
355    size_t size(void) const
356    {
357      return root_node() ? root_node()->size_ : 0;
358    }
359
360  private:
361    Compare compare_;
362    ranking::Impl impl_;
363
364    void print(const ranking::NodeBase* p, std::ostream& os) const
365    {
366      if (p) {
367        if (p->is_head_node()==false) {
368          print(p->right_, os);
369        }
370        os << std::string(p->generation()*4, ' ');
371        if (!p->is_head_node())
372          os << value(p);
373        else
374          os << "H";
375        os << ":   "
376                  << p->parent_ << " "
377                  << p << " "
378                  << p->left_ << " "
379                  << p->right_ << "\n";
380        if (p->is_head_node()==false) {
381          print(p->left_, os);
382        }
383        if (p->parent_ && !p->is_left_node() && !p->is_right_node()) {
384          os << "print error: " << p << "\n";
385          exit(1);
386        }
387      }
388    }
389
390    // return a copy of x but with children and parent set to nullptr.
391    ranking::NodeValue<T>*
392    clone_node(const ranking::NodeValue<T>* x) const;
393
394    /**
395       copy data in other.Impl_ into impl_
396
397       Basically copy constructor of Impl but nodes (except for head
398       node) are copied as NodeValue<T> and Impl is not aware of T.
399     */
400    ranking::NodeValue<T>* copy(const Ranking& other);
401
402    /**
403       Create a copy of root and return it
404     */
405    ranking::NodeValue<T>*
406    copy(const ranking::NodeValue<T>* root, ranking::NodeBase* h) const;
407
408    /**
409       Remove node position is pointing to
410     */
411    void erase_node(const_iterator position);
412
413    // return the root node
414    const ranking::NodeValue<T>* first_node(void) const
415    {
416      YAT_ASSERT(impl_.head_.parent_);
417      return static_cast<const ranking::NodeValue<T>*>(impl_.head_.parent_);
418    }
419
420
421    ranking::NodeValue<T>* first_node(void)
422    {
423      YAT_ASSERT(impl_.head_.parent_);
424      return static_cast<ranking::NodeValue<T>*>(impl_.head_.parent_);
425    }
426
427
428    const ranking::NodeBase* last_node(void) const
429    {
430      return &impl_.head_;
431    }
432
433
434    ranking::NodeBase* last_node(void)
435    {
436      return &impl_.head_;
437    }
438
439
440    const ranking::NodeValue<T>*
441    left(const ranking::NodeBase* x) const
442    {
443      YAT_ASSERT(x->left_ != &impl_.head_);
444      return static_cast<const ranking::NodeValue<T>*>(x->left_);
445    }
446
447
448    ranking::NodeValue<T>*
449    left(ranking::NodeBase* x) const
450    {
451      YAT_ASSERT(x->left_ != &impl_.head_);
452      return static_cast<ranking::NodeValue<T>*>(x->left_);
453    }
454
455
456    const ranking::NodeValue<T>*
457    right(const ranking::NodeBase* x) const
458    {
459      YAT_ASSERT(x->right_ != &impl_.head_);
460      return static_cast<const ranking::NodeValue<T>*>(x->right_);
461    }
462
463
464    ranking::NodeValue<T>*
465    right(ranking::NodeBase* x) const
466    {
467      YAT_ASSERT(x->right_ != &impl_.head_);
468      return static_cast<ranking::NodeValue<T>*>(x->right_);
469    }
470
471
472    // delete x and its offsprings
473    void erase(ranking::NodeValue<T>* x) const
474    {
475      while (x) {
476        if (x->right_ && x->right_ !=  &impl_.head_)
477          erase(right(x));
478        ranking::NodeValue<T>* tmp = left(x);
479        delete x;
480        x = tmp;
481      }
482    }
483
484
485    /**
486       traverse the tree and find a suitable leaf where we can insert
487       \c element and keep the tree sorted.
488     */
489    iterator insert(std::unique_ptr<ranking::NodeValue<T>>&& element)
490    {
491      iterator result(element.get());
492      if (empty()) {
493        YAT_ASSERT(root_node() == nullptr);
494        root_node() = element.release();
495        root_node()->right_ = &impl_.head_;
496        root_node()->height_ = 1;
497        root_node()->size_ = 1;
498        impl_.head_.left_ = root_node();
499
500        YAT_ASSERT(root_node()->validate());
501        YAT_ASSERT(impl_.head_.validate());
502        YAT_ASSERT(validate());
503        return result;
504      }
505
506      ranking::NodeBase* x = root_node();
507      YAT_ASSERT(x);
508      YAT_ASSERT(!x->is_head_node());
509
510      // element right of root
511      if (!compare_(element->value(), value(x))) {
512        // make new root parent of head
513        impl_.head_.parent_ = element.release();
514        impl_.head_.parent_->right_ = &impl_.head_;
515
516        // make old root and left child of new root
517        x->right_ = nullptr;
518        impl_.head_.parent_->left_ = x;
519        x->parent_ = impl_.head_.parent_;
520        YAT_ASSERT(x->size_ > 0);
521
522        impl_.head_.parent_->size_ = x->size_ + 1;
523        impl_.head_.parent_->height_ = x->height_ + 1;
524
525        YAT_ASSERT(x->validate());
526        YAT_ASSERT(impl_.head_.parent_);
527        YAT_ASSERT(impl_.head_.parent_->validate());
528        YAT_ASSERT(impl_.head_.left_);
529        YAT_ASSERT(impl_.head_.left_->validate());
530        YAT_ASSERT(validate());
531        return result;
532      }
533
534      ranking::NodeBase* parent = nullptr;
535      YAT_ASSERT(x);
536      while (true) {
537        parent = x;
538        if (compare_(element->value(), value(x))) {
539          x = x->left_;
540          if (x == nullptr) {
541            element->parent_ = parent;
542            parent->left_ = element.release();
543            parent->increment_size();
544            parent->update_height();
545            if (impl_.head_.left_ == parent)
546              impl_.head_.left_ = parent->left_;
547            YAT_ASSERT(validate());
548            return result;
549          }
550        }
551        else {
552          x = x->right_;
553          if (x == nullptr) {
554            element->parent_ = parent;
555            parent->right_ = element.release();
556            parent->increment_size();
557            parent->update_height();
558            YAT_ASSERT(validate());
559            return result;
560          }
561        }
562        YAT_ASSERT(x != &impl_.head_);
563        YAT_ASSERT(x != parent);
564      }
565    }
566
567
568    const_iterator
569    lower_bound(const ranking::NodeValue<T>* x, const ranking::NodeBase* y,
570                const T& key) const
571    {
572      if (compare_(x->value(), key))
573        return const_iterator(y);
574
575      while (x) {
576        // x value is greater than key, search in left branch
577        if (!compare_(x->value(), key)) {
578          y = x;
579          // asign x->left_ as NodeValue*
580          x = left(x);
581        }
582        else { // x value <= key, search in right branch but don't update y
583          YAT_ASSERT(x->right_ != &impl_.head_);
584          // asign x->right_ as NodeValue*
585          x = right(x);
586        }
587      }
588      return const_iterator(y);
589    }
590
591
592    /**
593       \return the root of the tree
594     */
595    ranking::NodeBase*& root_node(void)
596    {
597      return impl_.head_.parent_;
598    }
599
600
601    const ranking::NodeBase* const root_node(void) const
602    {
603      return impl_.head_.parent_;
604    }
605
606
607    ranking::NodeBase* left_most(void)
608    {
609      return impl_.head_.left_;
610    }
611
612
613    const ranking::NodeBase* left_most(void) const
614    {
615      return impl_.head_.left_;
616    }
617
618
619    const ranking::NodeValue<T>* parent(const ranking::NodeBase* x) const
620    {
621      YAT_ASSERT(x);
622      YAT_ASSERT(x->parent_);
623      YAT_ASSERT(x->parent_ != &impl_.head_);
624      return static_cast<const ranking::NodeValue<T>*>(x->parent_);
625    }
626
627
628    ranking::NodeValue<T>* parent(ranking::NodeBase* x) const
629    {
630      YAT_ASSERT(x);
631      YAT_ASSERT(x->parent_);
632      YAT_ASSERT(x->parent_ != &impl_.head_);
633      return static_cast<ranking::NodeValue<T>*>(x->parent_);
634    }
635
636
637    /*
638    ranking::NodeBase* right_most(void)
639    {
640      head_.right_;
641    }
642
643
644    const ranking::NodeBase* right_most(void) const
645    {
646      head_.right_;
647    }
648    */
649
650    const_iterator
651    upper_bound(const ranking::NodeValue<T>* x, const ranking::NodeBase* y,
652                const T& key) const
653    {
654      if (!compare_(key, x->value()))
655        return const_iterator(y);
656
657
658      while (x) {
659        // key is less than x value, search in left
660        if (compare_(key, x->value())) {
661          y = x;
662          x = left(x);
663        }
664        else {
665          YAT_ASSERT(x->right_ != &impl_.head_);
666          x = right(x);
667        }
668      }
669      return const_iterator(y);
670    }
671
672
673    const T& value(const ranking::NodeBase* p) const
674    {
675      YAT_ASSERT(p);
676      YAT_ASSERT(!p->is_head_node());
677      return static_cast<const ranking::NodeValue<T>*>(p)->value();
678    }
679
680
681    bool validate(void) const
682    {
683#ifdef YAT_DEBUG_RANKING
684      if (!impl_.validate())
685        return false;
686      bool ok = true;
687      size_t rank = 0;
688      for (auto it = cbegin(); it!=cend(); ++it) {
689        size_t r = ranking(it);
690        if (r != rank) {
691          std::cerr << "ranking: " << r << "; expected: " << rank << "\n";
692          std::cerr << "size: " << it.node_->size_ << "\n";
693          std::cerr << it.node_->parent_ << " "
694                    << it.node_->is_left_node() << " "
695                    << it.node_->is_right_node() << "\n---\n";
696          ok = false;
697        }
698        ++rank;
699      }
700      return ok;
701#else
702      return true;
703#endif
704    }
705  };
706
707  // avoid doxygen reading code below as it has problems to to match
708  // declarations and implementations unless matching perfectly.
709
710  /// \cond IGNORE_DOXYGEN
711
712  // implementations
713  template<typename T, typename C>
714  Ranking<T,C>::Ranking(const Ranking& other)
715    : compare_(other.compare())
716  {
717    if (!other.empty())
718      root_node() = copy(other);
719    YAT_ASSERT(validate());
720  }
721
722
723  template<typename T, typename C>
724  Ranking<T,C>::Ranking(Ranking&& other)
725    : compare_(std::move(other.compare())), impl_(std::move(other.impl_))
726  {
727    YAT_ASSERT(validate());
728  }
729
730
731  template<typename T, typename C>
732  Ranking<T, C>& Ranking<T, C>::operator=(const Ranking& other)
733  {
734    if (this != &other) {
735      Ranking tmp(other);
736      *this = std::move(tmp);
737    }
738    return *this;
739  }
740
741
742  template<typename T, typename C>
743  Ranking<T, C>& Ranking<T, C>::operator=(Ranking&& other)
744  {
745    clear();
746    compare_ = std::move(other.compare_);
747    impl_ = std::move(other.impl_);
748    return *this;
749  }
750
751
752  template<typename T, typename C>
753  ranking::NodeValue<T>* Ranking<T,C>::copy(const Ranking& other)
754  {
755    YAT_ASSERT(validate());
756    YAT_ASSERT(impl_.head_.parent_ == nullptr);
757    YAT_ASSERT(other.first_node());
758    ranking::NodeValue<T>* root = copy(other.first_node(), last_node());
759    root->parent_ = nullptr;
760    root->right_ = last_node();
761    last_node()->left_ = root->left_most();
762    last_node()->parent_ = root;
763    YAT_ASSERT(validate());
764    return root;
765  }
766
767
768  template<typename T, typename C>
769  ranking::NodeValue<T>* Ranking<T,C>::copy(const ranking::NodeValue<T>* x,
770                                            ranking::NodeBase* parent) const
771  {
772    YAT_ASSERT(x);
773    ranking::NodeValue<T>* root = clone_node(x);
774    root->height_ = x->height_;
775    root->size_ = x->size_;
776    YAT_ASSERT(root);
777    root->parent_ = parent;
778    try {
779      if (x->right_ && !x->right_->is_head_node()) {
780        YAT_ASSERT(x != right(x));
781        YAT_ASSERT(x->right_ != &impl_.head_);
782        root->right_ = copy(right(x), root);
783      }
784
785      parent = root;
786      x = left(x);
787      while (x) {
788        ranking::NodeValue<T>* y = clone_node(x);
789        y->height_ = x->height_;
790        y->size_ = x->size_;
791        parent->left_ = y;
792        y->parent_ = parent;
793        if (x->right_) {
794          YAT_ASSERT(x->right_ != &impl_.head_);
795          y->right_ = copy(right(x), y);
796        }
797        parent = y;
798        x = left(x);
799      }
800    }
801    catch (std::exception& e) {
802      erase(root);
803      std::rethrow_exception(std::current_exception());
804    }
805
806    return root;
807  }
808
809
810  template<typename T, typename C>
811  ranking::NodeValue<T>*
812  Ranking<T,C>::clone_node(const ranking::NodeValue<T>* x) const
813  {
814    YAT_ASSERT(x);
815    ranking::NodeValue<T>* res = new ranking::NodeValue<T>(x->value());
816    res->left_ = nullptr;
817    res->right_ = nullptr;
818    res->parent_ = nullptr;
819    return res;
820  }
821
822
823  template<typename T, typename C>
824  void Ranking<T, C>::erase_node(typename Ranking<T, C>::const_iterator p)
825  {
826    YAT_ASSERT(p != end());
827    const ranking::NodeBase* node = p.node_;
828    //    std::cerr << "erase_node: " << node << "\n";
829    YAT_ASSERT(node);
830
831    // two children
832    if (node->left_ && node->right_) {
833      // When node has two branches, we take the most leftmost node in
834      // the right branch and place in nodes place.
835      ranking::NodeBase* leftmost = node->right_->left_most();
836      YAT_ASSERT(leftmost->left_ == nullptr);
837
838      // If the leftmost node has a kid, we need to relink the kid
839      // with its grand parent
840      if (leftmost->parent_ != node) {
841        impl_.relink(leftmost, leftmost->right_);
842      }
843      impl_.relink(node, leftmost);
844      YAT_ASSERT(leftmost->left_ == node->left_);
845      YAT_ASSERT(!leftmost->left_ || leftmost->left_->parent_==leftmost);
846      leftmost->update_height();
847      leftmost->size_ =
848        1 + ranking::size(leftmost->left_) + ranking::size(leftmost->right_);
849      leftmost->parent_->decrement_size();
850      YAT_ASSERT(validate());
851    }
852    else {
853      // single child node is simple, the child takes the node's place
854      impl_.relink(node, node->left_ ? node->left_ : node->right_);
855      node->parent_->decrement_size();
856      node->parent_->update_height();
857      YAT_ASSERT(validate());
858    }
859    // FIXME we need to delete the node, but be careful to not delete
860    // any of ots children; perhaps const_cast first?
861
862  }
863
864
865  template<typename T, typename C>
866  typename Ranking<T, C>::iterator
867  Ranking<T, C>::erase(typename Ranking<T, C>::const_iterator p)
868  {
869    YAT_ASSERT(p != end());
870    const_iterator res = p;
871    ++res;
872    erase_node(p);
873    // iterator and const_iterator are same at the moment
874    return res;
875  }
876
877
878  template<typename T, typename C>
879  typename Ranking<T, C>::size_type Ranking<T, C>::erase(const T& value)
880  {
881    auto it = lower_bound(value);
882    typename Ranking<T, C>::size_type n = 0;
883    while (it!=end() && !compare_(value, *it)) {
884      erase_node(it++);
885      ++n;
886    }
887    return n;
888  }
889
890
891  template<typename T, typename C>
892  typename Ranking<T, C>::iterator
893  Ranking<T, C>::erase(typename Ranking<T, C>::const_iterator first,
894                       typename Ranking<T, C>::const_iterator last)
895  {
896    if (first == cbegin() && last == cend())
897      clear();
898    else
899      while (first != last) {
900        erase_node(first++);
901      }
902    return last;
903  }
904
905
906  template<typename T, typename C>
907  typename Ranking<T, C>::const_iterator Ranking<T, C>::find(const T& x) const
908  {
909    auto it = lower_bound(x);
910    if (it != cend() && compare_(x, *it))
911      it = cend();
912    return it;
913  }
914
915  /// \endcond
916
917}}} // of namespace utility, yat, and theplu
918#endif
Note: See TracBrowser for help on using the repository browser.