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

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

add a destructor; refs #710

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.0 KB
Line 
1#ifndef theplu_yat_utility_ranking
2#define theplu_yat_utility_ranking
3
4// $Id: Ranking.h 4074 2021-08-20 06:37:38Z 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       \brief Destructor
73     */
74    ~Ranking(void)
75    {
76      clear();
77    }
78
79    /**
80       Construct empty container with comparison function \c c.
81     */
82    Ranking(const Compare& c)
83      : compare_(c)
84    {
85      YAT_ASSERT(validate());
86    }
87
88
89    /**
90       \brief Copy constructor
91     */
92    Ranking(const Ranking& other);
93
94    /**
95       \brief move constructor
96     */
97    Ranking(Ranking&& other);
98
99    /**
100       \brief assignment operator
101     */
102    Ranking& operator=(const Ranking& other);
103
104    /**
105       \brief move assignment
106     */
107    Ranking& operator=(Ranking&& other);
108
109
110    /**
111       \return iterator pointing to the first element
112     */
113    iterator begin(void)
114    {
115      return iterator(impl_.left_most());
116    }
117
118
119    /**
120       \return iterator pointing to the first element
121     */
122    const_iterator begin(void) const
123    {
124      return cbegin();
125    }
126
127
128    /**
129       \return iterator pointing to the first element
130     */
131    const_iterator cbegin(void) const
132    {
133      return const_iterator(impl_.left_most());
134    }
135
136
137    /**
138       \return iterator pointing to one-passed-last element
139     */
140    iterator end(void)
141    {
142      return iterator(&impl_.head_);
143    }
144
145
146    /**
147       \return iterator pointing to one-passed-last element
148     */
149    const_iterator end(void) const
150    {
151      return cend();
152    }
153
154
155    /**
156       \return iterator pointing to one-passed-last element
157     */
158    const_iterator cend(void) const
159    {
160      return const_iterator(&impl_.head_);
161    }
162
163
164    /**
165       \return reverse iterator pointing to first element
166     */
167    reverse_iterator rbegin(void)
168    {
169      return reverse_iterator(end());
170    }
171
172
173    /**
174       \return reverse iterator pointing to one-passed-last element
175     */
176    reverse_iterator rend(void)
177    {
178      return reverse_iterator(begin());
179    }
180
181
182    /**
183       \return reverse iterator pointing to one-passed-last element
184     */
185    const_reverse_iterator rend(void) const
186    {
187      return crend();
188    }
189
190
191    /**
192       \return reverse iterator pointing to first element
193     */
194    const_reverse_iterator rbegin(void) const
195    {
196      return crbegin();
197    }
198
199
200    /**
201       \return reverse iterator pointing to first element
202     */
203    const_reverse_iterator crbegin(void) const
204    {
205      return const_reverse_iterator(cend());
206    }
207
208    /**
209       \return reverse iterator pointing to the one-passed-last element
210     */
211    const_reverse_iterator crend(void) const
212    {
213      return const_reverse_iterator(cbegin());
214    }
215
216
217    /**
218       Remove all nodes
219     */
220    void clear(void)
221    {
222      if (size()) {
223        YAT_ASSERT(root_node() != head_node());
224        erase(root_node());
225      }
226      impl_.reset();
227    }
228
229
230    /**
231       access comparison function which is used to sort elements
232     */
233    const Compare& compare(void) const
234    {
235      return compare_;
236    }
237
238
239    /**
240       \return true if (and only if) container has zero elements
241     */
242    bool empty(void) const
243    {
244      return impl_.empty();
245    }
246
247
248    /**
249       Remove element pointed to by \c position.
250
251       \return An iterator pointing to the element that follows the
252       last element removed.
253     */
254    iterator erase(const_iterator position);
255
256    /**
257       Erase all elements that are equivalent with \c value
258       \return number of elements removed
259     */
260    size_type erase(const T& value);
261
262    /**
263       Remove elements in range [first, last).
264
265       \return An iterator pointing to the element that follows the
266       last element removed.
267     */
268    iterator erase(const_iterator first, const_iterator last);
269
270    /**
271       Find an element that is equivalent to x
272     */
273    const_iterator find(const T& x) const;
274
275
276    /**
277       \brief insert an element
278     */
279    iterator insert(const T& element)
280    {
281      std::unique_ptr<ranking::NodeValue<T>>
282        newnode(new ranking::NodeValue<T>(element));
283      return insert(std::move(newnode));
284    }
285
286
287    /**
288       \brief insert an element
289     */
290    iterator insert(T&& element)
291    {
292      std::unique_ptr<ranking::NodeValue<T>>
293        newnode(new ranking::NodeValue<T>(std::move(element)));
294      return insert(std::move(newnode));
295    }
296
297
298    /**
299       \brief insert with hint
300     */
301    iterator insert(const_iterator hint, const T& element)
302    {
303      // FIXME use the hint
304      return insert(element);
305    }
306
307
308    /**
309       \brief insert with hint
310     */
311    iterator insert(const_iterator hint,  T&& element)
312    {
313      // FIXME use the hint
314      return insert(std::move(element));
315    }
316
317
318    /**
319       \brief insert range
320     */
321    template<typename InputIterator>
322    void insert(InputIterator first, InputIterator last)
323    {
324      for (; first!=last; ++first)
325        insert(end(), *first);
326    }
327
328
329    /**
330       \return the first element which is equal (or greater) to \c x
331     */
332    const_iterator lower_bound(const T& x) const
333    {
334      if (empty())
335        return cend();
336      return lower_bound(root_node(), head_node(), x);
337    }
338
339
340    /**
341       \return the first element which is greater than \c x
342     */
343    const_iterator upper_bound(const T& x) const
344    {
345      if (empty())
346        return cend();
347      return upper_bound(root_node(), head_node(), x);
348    }
349
350
351    /**
352       \return number of elements smaller than \c it
353     */
354    size_t ranking(const_iterator it) const
355    {
356      YAT_ASSERT(it.node_);
357      return impl_.ranking(it.node_);
358    }
359
360
361    /**
362       \return number of elements in container
363     */
364    size_t size(void) const
365    {
366      return impl_.size();
367    }
368
369  private:
370    Compare compare_;
371    ranking::Impl impl_;
372
373    void print(const ranking::NodeBase* p, std::ostream& os) const
374    {
375      if (p) {
376        if (p->is_head_node()==false) {
377          print(p->right_, os);
378        }
379        os << std::string(p->generation()*4, ' ');
380        if (!p->is_head_node())
381          os << value(p);
382        else
383          os << "H";
384        os << ", H=" << ranking::height(p) << ", S=" << ranking::size(p);
385        os << ":   "
386           << p->parent_ << " "
387           << p << " "
388           << p->left_ << " "
389           << p->right_ << "\n";
390        if (p->is_head_node()==false) {
391          print(p->left_, os);
392        }
393        if (p->parent_ && !p->is_left_node() && !p->is_right_node()) {
394          os << "print error: " << p << "\n";
395          exit(1);
396        }
397      }
398    }
399
400    // return a copy of x but with children and parent set to nullptr.
401    ranking::NodeValue<T>*
402    clone_node(const ranking::NodeValue<T>* x) const;
403
404    /**
405       copy data in other.Impl_ into impl_
406
407       Basically copy constructor of Impl but nodes (except for head
408       node) are copied as NodeValue<T> and Impl is not aware of T.
409     */
410    ranking::NodeValue<T>* copy(const Ranking& other);
411
412    /**
413       Create a copy of root and return it
414     */
415    ranking::NodeValue<T>* copy(const ranking::NodeValue<T>* root) const;
416
417    /**
418       Remove node position is pointing to
419     */
420    void erase_node(const_iterator position);
421
422    // return the root node
423    const ranking::NodeValue<T>* root_node(void) const
424    {
425      return static_cast<const ranking::NodeValue<T>*>(impl_.root_node());
426    }
427
428
429    ranking::NodeValue<T>* root_node(void)
430    {
431      return static_cast<ranking::NodeValue<T>*>(impl_.root_node());
432    }
433
434
435    const ranking::NodeBase* head_node(void) const
436    {
437      return &impl_.head_;
438    }
439
440
441    ranking::NodeBase* head_node(void)
442    {
443      return &impl_.head_;
444    }
445
446
447    const ranking::NodeValue<T>*
448    left(const ranking::NodeBase* x) const
449    {
450      YAT_ASSERT(x->left_ != &impl_.head_);
451      return static_cast<const ranking::NodeValue<T>*>(x->left_);
452    }
453
454
455    ranking::NodeValue<T>*
456    left(ranking::NodeBase* x) const
457    {
458      YAT_ASSERT(x->left_ != &impl_.head_);
459      return static_cast<ranking::NodeValue<T>*>(x->left_);
460    }
461
462
463    const ranking::NodeValue<T>*
464    right(const ranking::NodeBase* x) const
465    {
466      YAT_ASSERT(x->right_ != &impl_.head_);
467      return static_cast<const ranking::NodeValue<T>*>(x->right_);
468    }
469
470
471    ranking::NodeValue<T>*
472    right(ranking::NodeBase* x) const
473    {
474      YAT_ASSERT(x->right_ != &impl_.head_);
475      return static_cast<ranking::NodeValue<T>*>(x->right_);
476    }
477
478
479    // delete x and its offsprings
480    void erase(ranking::NodeValue<T>* x) const
481    {
482      while (x) {
483        if (x->right_ && x->right_ !=  &impl_.head_)
484          erase(right(x));
485        ranking::NodeValue<T>* tmp = left(x);
486        delete x;
487        x = tmp;
488      }
489    }
490
491
492    /**
493       traverse the tree and find a suitable leaf where we can insert
494       \c element and keep the tree sorted.
495     */
496    iterator insert(std::unique_ptr<ranking::NodeValue<T>>&& element)
497    {
498      iterator result(element.get());
499
500      if (empty()) {
501        element->parent_ = &impl_.head_;
502        impl_.root_node() = element.release();
503        impl_.head_.left_ = impl_.root_node();
504        impl_.head_.right_ = impl_.root_node();
505        impl_.head_.update_height();
506        impl_.head_.update_size();
507
508        YAT_ASSERT(impl_.root_node()->parent_);
509        YAT_ASSERT(impl_.root_node()->parent_ == &impl_.head_);
510        YAT_ASSERT(impl_.root_node()->is_left_node());
511
512        YAT_ASSERT(validate());
513        return result;
514      }
515
516      ranking::NodeBase* x = impl_.root_node();
517      YAT_ASSERT(x);
518      YAT_ASSERT(!x->is_head_node());
519
520      while (true) {
521        ranking::NodeBase* parent = x;
522        if (compare_(element->value(), value(x))) {
523          x = x->left_;
524          if (x == nullptr) {
525            impl_.insert_and_rebalance(std::move(element), *parent,
526                                       parent->left_);
527            if (impl_.left_most() == parent)
528              impl_.left_most() = parent->left_;
529            YAT_ASSERT(validate());
530            return result;
531          }
532        }
533        else {
534          x = x->right_;
535          if (x == nullptr) {
536            impl_.insert_and_rebalance(std::move(element), *parent,
537                                       parent->right_);
538            YAT_ASSERT(validate());
539            return result;
540          }
541        }
542      }
543      YAT_ASSERT(0 && "we can't reach here");
544      return result;
545    }
546
547
548    /*
549      Find the first node that is greater or equal to key, i.e., all
550      elements left of returned node are less than key.
551     */
552    const_iterator
553    lower_bound(const ranking::NodeValue<T>* x, const ranking::NodeBase* y,
554                const T& key) const
555    {
556      // x is used to traverse the tree
557      // y holds the result
558
559      while (x) {
560        // key is less (or equal) than x, store x as potential result
561        // and search in left branch
562        if (!compare_(x->value(), key)) {
563          y = x;
564          x = left(x);
565        }
566        // key is greater than x, the lower bound is not x; it is
567        // either in the right branch or a previously assigned
568        // ancestor. Do not store x as potential result, but search
569        // branch.
570        else
571          x = right(x);
572      }
573      // x has reached a leaf, and the result should be stored in y
574
575      // returned node is not smaller than key
576      YAT_ASSERT(y==head_node() || !compare_(value(y), key));
577      // all nodes left of returned node are smaller than key
578      YAT_ASSERT(y->left_==nullptr ||
579                 compare_(value(y->left_->right_most()), key));
580      return const_iterator(y);
581    }
582
583
584    const ranking::NodeValue<T>* parent(const ranking::NodeBase* x) const
585    {
586      YAT_ASSERT(x);
587      YAT_ASSERT(x->parent_);
588      YAT_ASSERT(x->parent_ != &impl_.head_);
589      return static_cast<const ranking::NodeValue<T>*>(x->parent_);
590    }
591
592
593    ranking::NodeValue<T>* parent(ranking::NodeBase* x) const
594    {
595      YAT_ASSERT(x);
596      YAT_ASSERT(x->parent_);
597      YAT_ASSERT(x->parent_ != &impl_.head_);
598      return static_cast<ranking::NodeValue<T>*>(x->parent_);
599    }
600
601
602    /*
603      Find the first node that is greater than key, i.e., all
604      elements left of returned node are less or equal to key.
605     */
606    const_iterator
607    upper_bound(const ranking::NodeValue<T>* x, const ranking::NodeBase* y,
608                const T& key) const
609    {
610      // x is used to traverse the tree
611      // y holds the result
612
613      while (x) {
614        // key is less than x value, x is a potential upper_bound,
615        // store and search in left
616        if (compare_(key, x->value())) {
617          y = x;
618          x = left(x);
619        }
620        else {
621          // key is greater (or equal) than x, x is not the upper
622          // bound. It is either in the right branch or in a
623          // previously assigned ancestor (current y).
624          x = right(x);
625        }
626      }
627      // x has reached a leaf, and the result should be stored in y
628
629      // key is less than returned node
630      YAT_ASSERT(y==head_node() || compare_(key, value(y)));
631      // all nodes left of returned node are smaller (or equal) than
632      // key, i.e., key is not smaller than any of the nodes to the
633      // left of returned node.
634      YAT_ASSERT(y->left_==nullptr ||
635                 !compare_(key, value(y->left_->right_most())));
636      return const_iterator(y);
637    }
638
639
640    const T& value(const ranking::NodeBase* p) const
641    {
642      YAT_ASSERT(p);
643      YAT_ASSERT(!p->is_head_node());
644      return static_cast<const ranking::NodeValue<T>*>(p)->value();
645    }
646
647
648    bool validate(void) const
649    {
650#ifndef YAT_DEBUG_RANKING
651      return true;
652#else
653      if (!impl_.validate()) {
654        std::cerr << "Impl::validate failed\n";
655        return false;
656      }
657
658      bool ok = true;
659      size_t rank = 0;
660      YAT_ASSERT(cbegin().node_);
661      YAT_ASSERT(cend().node_);
662      for (auto it = cbegin(); it!=cend(); ++it) {
663        size_t r = ranking(it);
664        if (r != rank) {
665          std::cerr << "ranking: " << r << "; expected: " << rank << "\n";
666          std::cerr << "size: " << it.node_->size_ << "\n";
667          std::cerr << it.node_->parent_ << " "
668                    << it.node_->is_left_node() << " "
669                    << it.node_->is_right_node() << "\n---\n";
670          ok = false;
671        }
672        ++rank;
673      }
674      return ok;
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      impl_.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(other.root_node());
728    ranking::NodeValue<T>* root = copy(other.root_node());
729    root->parent_ = head_node();
730    head_node()->left_ = root;
731    head_node()->right_ = root->left_most();
732    head_node()->update_height();
733    head_node()->update_size();
734    YAT_ASSERT(validate());
735    return root;
736  }
737
738
739  template<typename T, typename C>
740  ranking::NodeValue<T>*
741  Ranking<T,C>::copy(const ranking::NodeValue<T>* x) const
742  {
743    YAT_ASSERT(x);
744    ranking::NodeValue<T>* root = clone_node(x);
745    YAT_ASSERT(root);
746    root->height_ = x->height_;
747    root->size_ = x->size_;
748
749    try {
750      if (x->left_) {
751        root->left_ = copy(left(x));
752        root->left_->parent_ = root;
753      }
754      if (x->right_) {
755        root->right_ = copy(right(x));
756        root->right_->parent_ = root;
757      }
758    }
759    catch (std::exception& e) {
760      erase(root);
761      std::rethrow_exception(std::current_exception());
762    }
763    return root;
764  }
765
766
767  template<typename T, typename C>
768  ranking::NodeValue<T>*
769  Ranking<T,C>::clone_node(const ranking::NodeValue<T>* x) const
770  {
771    YAT_ASSERT(x);
772    ranking::NodeValue<T>* res = new ranking::NodeValue<T>(x->value());
773    res->left_ = nullptr;
774    res->right_ = nullptr;
775    res->parent_ = nullptr;
776    return res;
777  }
778
779
780  template<typename T, typename C>
781  void Ranking<T, C>::erase_node(typename Ranking<T, C>::const_iterator p)
782  {
783    YAT_ASSERT(p != end());
784    const ranking::NodeBase* node = p.node_;
785    YAT_ASSERT(node);
786
787    impl_.erase_and_rebalance(node);
788    delete node;
789    YAT_ASSERT(validate());
790    return;
791  }
792
793
794  template<typename T, typename C>
795  typename Ranking<T, C>::iterator
796  Ranking<T, C>::erase(typename Ranking<T, C>::const_iterator p)
797  {
798    YAT_ASSERT(p != end());
799    const_iterator res = p;
800    ++res;
801    erase_node(p);
802    // iterator and const_iterator are same at the moment
803    return res;
804  }
805
806
807  template<typename T, typename C>
808  typename Ranking<T, C>::size_type Ranking<T, C>::erase(const T& value)
809  {
810    auto it = lower_bound(value);
811    typename Ranking<T, C>::size_type n = 0;
812    while (it!=end() && !compare_(value, *it)) {
813      erase_node(it++);
814      ++n;
815    }
816    return n;
817  }
818
819
820  template<typename T, typename C>
821  typename Ranking<T, C>::iterator
822  Ranking<T, C>::erase(typename Ranking<T, C>::const_iterator first,
823                       typename Ranking<T, C>::const_iterator last)
824  {
825    if (first == cbegin() && last == cend())
826      clear();
827    else
828      while (first != last) {
829        erase_node(first++);
830      }
831    return last;
832  }
833
834
835  template<typename T, typename C>
836  typename Ranking<T, C>::const_iterator Ranking<T, C>::find(const T& x) const
837  {
838    auto it = lower_bound(x);
839    if (it != cend() && compare_(x, *it))
840      it = cend();
841    return it;
842  }
843
844  /// \endcond
845
846}}} // of namespace utility, yat, and theplu
847#endif
Note: See TracBrowser for help on using the repository browser.