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

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

refs #710; add erase functions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.1 KB
Line 
1#ifndef theplu_yat_utility_ranking
2#define theplu_yat_utility_ranking
3
4// $Id: Ranking.h 4070 2021-08-09 06:32:59Z 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 size()==0;
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      // FIXME
349      return std::distance(cbegin(), it);
350    }
351
352
353    /**
354       \return number of elements in container
355     */
356    size_t size(void) const
357    {
358      return impl_.node_count_;
359    }
360
361  private:
362    Compare compare_;
363    ranking::Impl impl_;
364
365    void print(const ranking::NodeBase* p) const
366    {
367      if (p) {
368        if (p->is_head_node()==false) {
369          print(p->right_);
370        }
371        std::cerr << std::string(p->generation()*4, ' ');
372        if (!p->is_head_node())
373          std::cerr << static_cast<const ranking::NodeValue<T>*>(p)->value();
374        else
375          std::cerr << "H";
376        std::cerr << ":   "
377                  << p->parent_ << " "
378                  << p << " "
379                  << p->left_ << " "
380                  << p->right_ << "\n";
381        if (p->is_head_node()==false) {
382          print(p->left_);
383        }
384        if (p->parent_ && !p->is_left_node() && !p->is_right_node()) {
385          std::cerr << "print error: " << p << "\n";
386          exit(1);
387        }
388      }
389    }
390
391    // return a copy of x but with children and parent set to nullptr.
392    ranking::NodeValue<T>*
393    clone_node(const ranking::NodeValue<T>* x) const;
394
395    /**
396       copy data in other.Impl_ into impl_
397
398       Basically copy constructor of Impl but nodes (except for head
399       node) are copied as NodeValue<T> and Impl is not aware of T.
400     */
401    ranking::NodeValue<T>* copy(const Ranking& other);
402
403    /**
404       Create a copy of root and return it
405     */
406    ranking::NodeValue<T>*
407    copy(const ranking::NodeValue<T>* root, ranking::NodeBase* h) const;
408
409    /**
410       Remove node position is pointing to
411     */
412    void erase_node(const_iterator position);
413
414    // return the root node
415    const ranking::NodeValue<T>* first_node(void) const
416    {
417      YAT_ASSERT(impl_.head_.parent_);
418      return static_cast<const ranking::NodeValue<T>*>(impl_.head_.parent_);
419    }
420
421
422    ranking::NodeValue<T>* first_node(void)
423    {
424      YAT_ASSERT(impl_.head_.parent_);
425      return static_cast<ranking::NodeValue<T>*>(impl_.head_.parent_);
426    }
427
428
429    const ranking::NodeBase* last_node(void) const
430    {
431      return &impl_.head_;
432    }
433
434
435    ranking::NodeBase* last_node(void)
436    {
437      return &impl_.head_;
438    }
439
440
441    const ranking::NodeValue<T>*
442    left(const ranking::NodeBase* x) const
443    {
444      YAT_ASSERT(x->left_ != &impl_.head_);
445      return static_cast<const ranking::NodeValue<T>*>(x->left_);
446    }
447
448
449    ranking::NodeValue<T>*
450    left(ranking::NodeBase* x) const
451    {
452      YAT_ASSERT(x->left_ != &impl_.head_);
453      return static_cast<ranking::NodeValue<T>*>(x->left_);
454    }
455
456
457    const ranking::NodeValue<T>*
458    right(const ranking::NodeBase* x) const
459    {
460      YAT_ASSERT(x->right_ != &impl_.head_);
461      return static_cast<const ranking::NodeValue<T>*>(x->right_);
462    }
463
464
465    ranking::NodeValue<T>*
466    right(ranking::NodeBase* x) const
467    {
468      YAT_ASSERT(x->right_ != &impl_.head_);
469      return static_cast<ranking::NodeValue<T>*>(x->right_);
470    }
471
472
473    // delete x and its offsprings
474    void erase(ranking::NodeValue<T>* x) const
475    {
476      while (x) {
477        if (x->right_ && x->right_ !=  &impl_.head_)
478          erase(right(x));
479        ranking::NodeValue<T>* tmp = left(x);
480        delete x;
481        x = tmp;
482      }
483    }
484
485
486    /**
487       traverse the tree and find a suitable leaf where we can insert
488       \c element and keep the tree sorted.
489     */
490    iterator insert(std::unique_ptr<ranking::NodeValue<T>>&& element)
491    {
492      iterator result(element.get());
493      if (empty()) {
494        YAT_ASSERT(root_node() == nullptr);
495        root_node() = element.release();
496        root_node()->right_ = &impl_.head_;
497        impl_.head_.left_ = root_node();
498        ++impl_.node_count_;
499        YAT_ASSERT(root_node()->validate());
500        YAT_ASSERT(impl_.head_.validate());
501        YAT_ASSERT(validate());
502        return result;
503      }
504
505      ranking::NodeBase* x = root_node();
506      YAT_ASSERT(x);
507      YAT_ASSERT(!x->is_head_node());
508
509      // element right of root
510      if (!compare_(element->value(),
511                    static_cast<ranking::NodeValue<T>*>(x)->value())) {
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
521        ++impl_.node_count_;
522        YAT_ASSERT(x->validate());
523        YAT_ASSERT(impl_.head_.parent_);
524        YAT_ASSERT(impl_.head_.parent_->validate());
525        YAT_ASSERT(impl_.head_.left_);
526        YAT_ASSERT(impl_.head_.left_->validate());
527        YAT_ASSERT(validate());
528        return result;
529      }
530
531      ranking::NodeBase* parent = nullptr;
532      YAT_ASSERT(x);
533      while (true) {
534        parent = x;
535        if (compare_(element->value(),
536                     static_cast<ranking::NodeValue<T>*>(x)->value())) {
537          x = x->left_;
538          if (x == nullptr) {
539            element->parent_ = parent;
540            parent->left_ = element.release();
541            if (impl_.head_.left_ == parent)
542              impl_.head_.left_ = parent->left_;
543            ++impl_.node_count_;
544            YAT_ASSERT(validate());
545            return result;
546          }
547        }
548        else {
549          x = x->right_;
550          if (x == nullptr) {
551            element->parent_ = parent;
552            parent->right_ = element.release();
553            ++impl_.node_count_;
554            YAT_ASSERT(validate());
555            return result;
556          }
557        }
558        YAT_ASSERT(x != &impl_.head_);
559        YAT_ASSERT(x != parent);
560      }
561    }
562
563
564    const_iterator
565    lower_bound(const ranking::NodeValue<T>* x, const ranking::NodeBase* y,
566                const T& key) const
567    {
568      if (compare_(x->value(), key))
569        return const_iterator(y);
570
571      while (x) {
572        // x value is greater than key, search in left branch
573        if (!compare_(x->value(), key)) {
574          y = x;
575          // asign x->left_ as NodeValue*
576          x = left(x);
577        }
578        else { // x value <= key, search in right branch but don't update y
579          YAT_ASSERT(x->right_ != &impl_.head_);
580          // asign x->right_ as NodeValue*
581          x = right(x);
582        }
583      }
584      return const_iterator(y);
585    }
586
587
588    /**
589       \return the root of the tree
590     */
591    ranking::NodeBase*& root_node(void)
592    {
593      return impl_.head_.parent_;
594    }
595
596
597    const ranking::NodeBase* const root_node(void) const
598    {
599      return impl_.head_.parent_;
600    }
601
602
603    ranking::NodeBase* left_most(void)
604    {
605      return impl_.head_.left_;
606    }
607
608
609    const ranking::NodeBase* left_most(void) const
610    {
611      return impl_.head_.left_;
612    }
613
614
615    const ranking::NodeValue<T>* parent(const ranking::NodeBase* x) const
616    {
617      YAT_ASSERT(x);
618      YAT_ASSERT(x->parent_);
619      YAT_ASSERT(x->parent_ != &impl_.head_);
620      return static_cast<const ranking::NodeValue<T>*>(x->parent_);
621    }
622
623
624    ranking::NodeValue<T>* parent(ranking::NodeBase* x) const
625    {
626      YAT_ASSERT(x);
627      YAT_ASSERT(x->parent_);
628      YAT_ASSERT(x->parent_ != &impl_.head_);
629      return static_cast<ranking::NodeValue<T>*>(x->parent_);
630    }
631
632
633    /*
634    ranking::NodeBase* right_most(void)
635    {
636      head_.right_;
637    }
638
639
640    const ranking::NodeBase* right_most(void) const
641    {
642      head_.right_;
643    }
644    */
645
646    const_iterator
647    upper_bound(const ranking::NodeValue<T>* x, const ranking::NodeBase* y,
648                const T& key) const
649    {
650      if (!compare_(key, x->value()))
651        return const_iterator(y);
652
653
654      while (x) {
655        // key is less than x value, search in left
656        if (compare_(key, x->value())) {
657          y = x;
658          x = left(x);
659        }
660        else {
661          YAT_ASSERT(x->right_ != &impl_.head_);
662          x = right(x);
663        }
664      }
665      return const_iterator(y);
666    }
667
668
669    bool validate(void) const
670    {
671#ifdef YAT_DEBUG_RANKING
672      return impl_.validate();
673#else
674      return true;
675#endif
676    }
677  };
678
679  // avoid doxygen reading code below as it has problems to to match
680  // declarations and implementations unless matching perfectly.
681
682  /// \cond IGNORE_DOXYGEN
683
684  // implementations
685  template<typename T, typename C>
686  Ranking<T,C>::Ranking(const Ranking& other)
687    : compare_(other.compare())
688  {
689    if (!other.empty())
690      root_node() = copy(other);
691    YAT_ASSERT(validate());
692  }
693
694
695  template<typename T, typename C>
696  Ranking<T,C>::Ranking(Ranking&& other)
697    : compare_(std::move(other.compare())), impl_(std::move(other.impl_))
698  {
699    YAT_ASSERT(validate());
700  }
701
702
703  template<typename T, typename C>
704  Ranking<T, C>& Ranking<T, C>::operator=(const Ranking& other)
705  {
706    if (this != &other) {
707      Ranking tmp(other);
708      *this = std::move(tmp);
709    }
710    return *this;
711  }
712
713
714  template<typename T, typename C>
715  Ranking<T, C>& Ranking<T, C>::operator=(Ranking&& other)
716  {
717    clear();
718    compare_ = std::move(other.compare_);
719    impl_ = std::move(other.impl_);
720    return *this;
721  }
722
723
724  template<typename T, typename C>
725  ranking::NodeValue<T>* Ranking<T,C>::copy(const Ranking& other)
726  {
727    YAT_ASSERT(validate());
728    YAT_ASSERT(impl_.head_.parent_ == nullptr);
729    YAT_ASSERT(other.first_node());
730    ranking::NodeValue<T>* root = copy(other.first_node(), last_node());
731    root->parent_ = nullptr;
732    root->right_ = last_node();
733    last_node()->left_ = root->left_most();
734    last_node()->parent_ = root;
735    impl_.node_count_ = other.size();
736    YAT_ASSERT(validate());
737    return root;
738  }
739
740
741  template<typename T, typename C>
742  ranking::NodeValue<T>* Ranking<T,C>::copy(const ranking::NodeValue<T>* x,
743                                            ranking::NodeBase* parent) const
744  {
745    YAT_ASSERT(x);
746    ranking::NodeValue<T>* root = clone_node(x);
747    YAT_ASSERT(root);
748    root->parent_ = parent;
749    try {
750      if (x->right_ && !x->right_->is_head_node()) {
751        YAT_ASSERT(x != right(x));
752        YAT_ASSERT(x->right_ != &impl_.head_);
753        root->right_ = copy(right(x), root);
754      }
755
756      parent = root;
757      x = left(x);
758      while (x) {
759        ranking::NodeValue<T>* y = clone_node(x);
760        parent->left_ = y;
761        y->parent_ = parent;
762        if (x->right_) {
763          YAT_ASSERT(x->right_ != &impl_.head_);
764          y->right_ = copy(right(x), y);
765        }
766        parent = y;
767        x = left(x);
768      }
769    }
770    catch (std::exception& e) {
771      erase(root);
772      std::rethrow_exception(std::current_exception());
773    }
774
775    return root;
776  }
777
778
779  template<typename T, typename C>
780  ranking::NodeValue<T>*
781  Ranking<T,C>::clone_node(const ranking::NodeValue<T>* x) const
782  {
783    YAT_ASSERT(x);
784    ranking::NodeValue<T>* res = new ranking::NodeValue<T>(x->value());
785    res->left_ = nullptr;
786    res->right_ = nullptr;
787    res->parent_ = nullptr;
788    return res;
789  }
790
791
792  template<typename T, typename C>
793  void Ranking<T, C>::erase_node(typename Ranking<T, C>::const_iterator p)
794  {
795    YAT_ASSERT(p != end());
796    const ranking::NodeBase* node = p.node_;
797    YAT_ASSERT(node);
798
799    // two children
800    if (node->left_ && node->right_) {
801      ranking::NodeBase* leftmost = node->right_->left_most();
802      YAT_ASSERT(leftmost->left_ == nullptr);
803      if (leftmost->parent_ != node)
804        impl_.relink(leftmost, leftmost->right_);
805      impl_.relink(node, leftmost);
806    }
807    else {
808      // single child node is simple, the child takes the node's place
809      impl_.relink(node, node->left_ ? node->left_ : node->right_);
810    }
811    // FIXME we need to delete the node, but be careful to not delete
812    // any of ots children; perhaps const_cast first?
813
814    --impl_.node_count_;
815    YAT_ASSERT(validate());
816  }
817
818
819  template<typename T, typename C>
820  typename Ranking<T, C>::iterator
821  Ranking<T, C>::erase(typename Ranking<T, C>::const_iterator p)
822  {
823    YAT_ASSERT(p != end());
824    const_iterator res = p;
825    ++res;
826    erase_node(p);
827    // iterator and const_iterator are same at the moment
828    return res;
829  }
830
831
832  template<typename T, typename C>
833  typename Ranking<T, C>::size_type Ranking<T, C>::erase(const T& value)
834  {
835    auto it = lower_bound(value);
836    typename Ranking<T, C>::size_type n = 0;
837    while (it!=end() && !compare_(value, *it)) {
838      erase_node(it++);
839      ++n;
840    }
841    return n;
842  }
843
844
845  template<typename T, typename C>
846  typename Ranking<T, C>::iterator
847  Ranking<T, C>::erase(typename Ranking<T, C>::const_iterator first,
848                       typename Ranking<T, C>::const_iterator last)
849  {
850    if (first == cbegin() && last == cend())
851      clear();
852    else
853      while (first != last) {
854        erase_node(first++);
855      }
856    return last;
857  }
858
859
860  template<typename T, typename C>
861  typename Ranking<T, C>::const_iterator Ranking<T, C>::find(const T& x) const
862  {
863    auto it = lower_bound(x);
864    if (it != cend() && compare_(x, *it))
865      it = cend();
866    return it;
867  }
868
869  /// \endcond
870
871}}} // of namespace utility, yat, and theplu
872#endif
Note: See TracBrowser for help on using the repository browser.