#pragma once #include template struct TAvlTreeItem; template class TAvlTree: public TNonCopyable { using TTreeItem = TAvlTreeItem; friend struct TAvlTreeItem; static inline const T* AsT(const TTreeItem* item) noexcept { return (const T*)item; } static inline T* AsT(TTreeItem* item) noexcept { return (T*)item; } template class TIteratorBase { public: inline TIteratorBase(TTreeItem* p, const TAvlTree* t) noexcept : Ptr_(p) , Tree_(t) { } inline bool IsEnd() const noexcept { return Ptr_ == nullptr; } inline bool IsBegin() const noexcept { return Ptr_ == nullptr; } inline bool IsFirst() const noexcept { return Ptr_ && Ptr_ == Tree_->Head_; } inline bool IsLast() const noexcept { return Ptr_ && Ptr_ == Tree_->Tail_; } inline TValue& operator*() const noexcept { return *AsT(Ptr_); } inline TValue* operator->() const noexcept { return AsT(Ptr_); } inline TTreeItem* Inc() noexcept { return Ptr_ = FindNext(Ptr_); } inline TTreeItem* Dec() noexcept { return Ptr_ = FindPrev(Ptr_); } inline TIteratorBase& operator++() noexcept { Inc(); return *this; } inline TIteratorBase operator++(int) noexcept { TIteratorBase ret(*this); Inc(); return ret; } inline TIteratorBase& operator--() noexcept { Dec(); return *this; } inline TIteratorBase operator--(int) noexcept { TIteratorBase ret(*this); Dec(); return ret; } inline TIteratorBase Next() const noexcept { return ConstructNext(*this); } inline TIteratorBase Prev() const noexcept { return ConstructPrev(*this); } inline bool operator==(const TIteratorBase& r) const noexcept { return Ptr_ == r.Ptr_; } inline bool operator!=(const TIteratorBase& r) const noexcept { return Ptr_ != r.Ptr_; } private: inline static TIteratorBase ConstructNext(const TIteratorBase& i) noexcept { return TIterator(FindNext(i.Ptr_), i.Tree_); } inline static TIteratorBase ConstructPrev(const TIteratorBase& i) noexcept { return TIterator(FindPrev(i.Ptr_), i.Tree_); } inline static TIteratorBase FindPrev(TTreeItem* el) noexcept { if (el->Left_ != nullptr) { el = el->Left_; while (el->Right_ != nullptr) { el = el->Right_; } } else { while (true) { TTreeItem* last = el; el = el->Parent_; if (el == nullptr || el->Right_ == last) { break; } } } return el; } static TTreeItem* FindNext(TTreeItem* el) { if (el->Right_ != nullptr) { el = el->Right_; while (el->Left_) { el = el->Left_; } } else { while (true) { TTreeItem* last = el; el = el->Parent_; if (el == nullptr || el->Left_ == last) { break; } } } return el; } private: TTreeItem* Ptr_; const TAvlTree* Tree_; }; using TConstIterator = TIteratorBase; using TIterator = TIteratorBase; static inline TConstIterator ConstructFirstConst(const TAvlTree* t) noexcept { return TConstIterator(t->Head_, t); } static inline TIterator ConstructFirst(const TAvlTree* t) noexcept { return TIterator(t->Head_, t); } static inline TConstIterator ConstructLastConst(const TAvlTree* t) noexcept { return TConstIterator(t->Tail_, t); } static inline TIterator ConstructLast(const TAvlTree* t) noexcept { return TIterator(t->Tail_, t); } static inline bool Compare(const TTreeItem& l, const TTreeItem& r) { return C::Compare(*AsT(&l), *AsT(&r)); } public: using const_iterator = TConstIterator; using iterator = TIterator; inline TAvlTree() noexcept : Root_(nullptr) , Head_(nullptr) , Tail_(nullptr) { } inline ~TAvlTree() noexcept { Clear(); } inline void Clear() noexcept { for (iterator it = Begin(); it != End();) { (it++)->TTreeItem::Unlink(); } } inline T* Insert(TTreeItem* el, TTreeItem** lastFound = nullptr) noexcept { el->Unlink(); el->Tree_ = this; TTreeItem* curEl = Root_; TTreeItem* parentEl = nullptr; TTreeItem* lastLess = nullptr; while (true) { if (curEl == nullptr) { AttachRebal(el, parentEl, lastLess); if (lastFound != nullptr) { *lastFound = el; } return AsT(el); } if (Compare(*el, *curEl)) { parentEl = lastLess = curEl; curEl = curEl->Left_; } else if (Compare(*curEl, *el)) { parentEl = curEl; curEl = curEl->Right_; } else { if (lastFound != nullptr) { *lastFound = curEl; } return nullptr; } } } inline T* Find(const TTreeItem* el) const noexcept { TTreeItem* curEl = Root_; while (curEl) { if (Compare(*el, *curEl)) { curEl = curEl->Left_; } else if (Compare(*curEl, *el)) { curEl = curEl->Right_; } else { return AsT(curEl); } } return nullptr; } inline T* LowerBound(const TTreeItem* el) const noexcept { TTreeItem* curEl = Root_; TTreeItem* lowerBound = nullptr; while (curEl) { if (Compare(*el, *curEl)) { lowerBound = curEl; curEl = curEl->Left_; } else if (Compare(*curEl, *el)) { curEl = curEl->Right_; } else { return AsT(curEl); } } return AsT(lowerBound); } inline T* Erase(TTreeItem* el) noexcept { if (el->Tree_ == this) { return this->EraseImpl(el); } return nullptr; } inline T* EraseImpl(TTreeItem* el) noexcept { el->Tree_ = nullptr; TTreeItem* replacement; TTreeItem* fixfrom; long lheight, rheight; if (el->Right_) { replacement = el->Right_; while (replacement->Left_) { replacement = replacement->Left_; } if (replacement->Parent_ == el) { fixfrom = replacement; } else { fixfrom = replacement->Parent_; } if (el == Head_) { Head_ = replacement; } RemoveEl(replacement, replacement->Right_); ReplaceEl(el, replacement); } else if (el->Left_) { replacement = el->Left_; while (replacement->Right_) { replacement = replacement->Right_; } if (replacement->Parent_ == el) { fixfrom = replacement; } else { fixfrom = replacement->Parent_; } if (el == Tail_) { Tail_ = replacement; } RemoveEl(replacement, replacement->Left_); ReplaceEl(el, replacement); } else { fixfrom = el->Parent_; if (el == Head_) { Head_ = el->Parent_; } if (el == Tail_) { Tail_ = el->Parent_; } RemoveEl(el, nullptr); } if (fixfrom == nullptr) { return AsT(el); } RecalcHeights(fixfrom); TTreeItem* ub = FindFirstUnbalEl(fixfrom); while (ub) { lheight = ub->Left_ ? ub->Left_->Height_ : 0; rheight = ub->Right_ ? ub->Right_->Height_ : 0; if (rheight > lheight) { ub = ub->Right_; lheight = ub->Left_ ? ub->Left_->Height_ : 0; rheight = ub->Right_ ? ub->Right_->Height_ : 0; if (rheight > lheight) { ub = ub->Right_; } else if (rheight < lheight) { ub = ub->Left_; } else { ub = ub->Right_; } } else { ub = ub->Left_; lheight = ub->Left_ ? ub->Left_->Height_ : 0; rheight = ub->Right_ ? ub->Right_->Height_ : 0; if (rheight > lheight) { ub = ub->Right_; } else if (rheight < lheight) { ub = ub->Left_; } else { ub = ub->Left_; } } fixfrom = Rebalance(ub); ub = FindFirstUnbalEl(fixfrom); } return AsT(el); } inline const_iterator First() const noexcept { return ConstructFirstConst(this); } inline const_iterator Last() const noexcept { return ConstructLastConst(this); } inline const_iterator Begin() const noexcept { return First(); } inline const_iterator End() const noexcept { return const_iterator(nullptr, this); } inline const_iterator begin() const noexcept { return Begin(); } inline const_iterator end() const noexcept { return End(); } inline const_iterator cbegin() const noexcept { return Begin(); } inline const_iterator cend() const noexcept { return End(); } inline iterator First() noexcept { return ConstructFirst(this); } inline iterator Last() noexcept { return ConstructLast(this); } inline iterator Begin() noexcept { return First(); } inline iterator End() noexcept { return iterator(nullptr, this); } inline iterator begin() noexcept { return Begin(); } inline iterator end() noexcept { return End(); } inline bool Empty() const noexcept { return const_cast(this)->Begin() == const_cast(this)->End(); } inline explicit operator bool() const noexcept { return !this->Empty(); } template inline void ForEach(Functor& f) { iterator it = Begin(); while (!it.IsEnd()) { iterator next = it; ++next; f(*it); it = next; } } private: inline TTreeItem* Rebalance(TTreeItem* n) noexcept { long lheight, rheight; TTreeItem* a; TTreeItem* b; TTreeItem* c; TTreeItem* t1; TTreeItem* t2; TTreeItem* t3; TTreeItem* t4; TTreeItem* p = n->Parent_; TTreeItem* gp = p->Parent_; TTreeItem* ggp = gp->Parent_; if (gp->Right_ == p) { if (p->Right_ == n) { a = gp; b = p; c = n; t1 = gp->Left_; t2 = p->Left_; t3 = n->Left_; t4 = n->Right_; } else { a = gp; b = n; c = p; t1 = gp->Left_; t2 = n->Left_; t3 = n->Right_; t4 = p->Right_; } } else { if (p->Right_ == n) { a = p; b = n; c = gp; t1 = p->Left_; t2 = n->Left_; t3 = n->Right_; t4 = gp->Right_; } else { a = n; b = p; c = gp; t1 = n->Left_; t2 = n->Right_; t3 = p->Right_; t4 = gp->Right_; } } if (ggp == nullptr) { Root_ = b; } else if (ggp->Left_ == gp) { ggp->Left_ = b; } else { ggp->Right_ = b; } b->Parent_ = ggp; b->Left_ = a; a->Parent_ = b; b->Right_ = c; c->Parent_ = b; a->Left_ = t1; if (t1 != nullptr) { t1->Parent_ = a; } a->Right_ = t2; if (t2 != nullptr) { t2->Parent_ = a; } c->Left_ = t3; if (t3 != nullptr) { t3->Parent_ = c; } c->Right_ = t4; if (t4 != nullptr) { t4->Parent_ = c; } lheight = a->Left_ ? a->Left_->Height_ : 0; rheight = a->Right_ ? a->Right_->Height_ : 0; a->Height_ = (lheight > rheight ? lheight : rheight) + 1; lheight = c->Left_ ? c->Left_->Height_ : 0; rheight = c->Right_ ? c->Right_->Height_ : 0; c->Height_ = (lheight > rheight ? lheight : rheight) + 1; lheight = a->Height_; rheight = c->Height_; b->Height_ = (lheight > rheight ? lheight : rheight) + 1; RecalcHeights(ggp); return ggp; } inline void RecalcHeights(TTreeItem* el) noexcept { long lheight, rheight, new_height; while (el) { lheight = el->Left_ ? el->Left_->Height_ : 0; rheight = el->Right_ ? el->Right_->Height_ : 0; new_height = (lheight > rheight ? lheight : rheight) + 1; if (new_height == el->Height_) { return; } else { el->Height_ = new_height; } el = el->Parent_; } } inline TTreeItem* FindFirstUnbalGP(TTreeItem* el) noexcept { long lheight, rheight, balanceProp; TTreeItem* gp; if (el == nullptr || el->Parent_ == nullptr || el->Parent_->Parent_ == nullptr) { return nullptr; } gp = el->Parent_->Parent_; while (gp != nullptr) { lheight = gp->Left_ ? gp->Left_->Height_ : 0; rheight = gp->Right_ ? gp->Right_->Height_ : 0; balanceProp = lheight - rheight; if (balanceProp < -1 || balanceProp > 1) { return el; } el = el->Parent_; gp = gp->Parent_; } return nullptr; } inline TTreeItem* FindFirstUnbalEl(TTreeItem* el) noexcept { if (el == nullptr) { return nullptr; } while (el) { const long lheight = el->Left_ ? el->Left_->Height_ : 0; const long rheight = el->Right_ ? el->Right_->Height_ : 0; const long balanceProp = lheight - rheight; if (balanceProp < -1 || balanceProp > 1) { return el; } el = el->Parent_; } return nullptr; } inline void ReplaceEl(TTreeItem* el, TTreeItem* replacement) noexcept { TTreeItem* parent = el->Parent_; TTreeItem* left = el->Left_; TTreeItem* right = el->Right_; replacement->Left_ = left; if (left) { left->Parent_ = replacement; } replacement->Right_ = right; if (right) { right->Parent_ = replacement; } replacement->Parent_ = parent; if (parent) { if (parent->Left_ == el) { parent->Left_ = replacement; } else { parent->Right_ = replacement; } } else { Root_ = replacement; } replacement->Height_ = el->Height_; } inline void RemoveEl(TTreeItem* el, TTreeItem* filler) noexcept { TTreeItem* parent = el->Parent_; if (parent) { if (parent->Left_ == el) { parent->Left_ = filler; } else { parent->Right_ = filler; } } else { Root_ = filler; } if (filler) { filler->Parent_ = parent; } return; } inline void AttachRebal(TTreeItem* el, TTreeItem* parentEl, TTreeItem* lastLess) { el->Parent_ = parentEl; el->Left_ = nullptr; el->Right_ = nullptr; el->Height_ = 1; if (parentEl != nullptr) { if (lastLess == parentEl) { parentEl->Left_ = el; } else { parentEl->Right_ = el; } if (Head_->Left_ == el) { Head_ = el; } if (Tail_->Right_ == el) { Tail_ = el; } } else { Root_ = el; Head_ = Tail_ = el; } RecalcHeights(parentEl); TTreeItem* ub = FindFirstUnbalGP(el); if (ub != nullptr) { Rebalance(ub); } } private: TTreeItem* Root_; TTreeItem* Head_; TTreeItem* Tail_; }; template struct TAvlTreeItem: public TNonCopyable { public: using TTree = TAvlTree; friend class TAvlTree; friend typename TAvlTree::TConstIterator; friend typename TAvlTree::TIterator; inline TAvlTreeItem() noexcept : Left_(nullptr) , Right_(nullptr) , Parent_(nullptr) , Height_(0) , Tree_(nullptr) { } inline ~TAvlTreeItem() noexcept { Unlink(); } inline void Unlink() noexcept { if (Tree_) { Tree_->EraseImpl(this); } } private: TAvlTreeItem* Left_; TAvlTreeItem* Right_; TAvlTreeItem* Parent_; long Height_; TTree* Tree_; };