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

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

delete erased node

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