////////////////////////////////////////////////////////////////////////////////// /** \file \brief \ru Cбалансированное дерево. \en Balanced tree. \~ */ // \ru Никлаус Вирт "Алгоритмы и структуры данных" \en Niklaus Wirth "Algorithms and Data Structures" // \ru Построение сбалансированного дерева (АВЛ- дерево). Разновидность бинарного дерева. \en Construction of balanced tree (AVL-tree). There is a sort of binary tree. // \ru Из узла выходит не более двух поддеревьев. \en Each node contains at most two child subtrees. // \ru Дерево называется сбалансированным, когда высоты двух поддеревьев из его вершин \en Tree is balanced if heights of two child subtrees of any node // \ru отличаются не более чем на единицу. \en differ by at most one. // // \ru BalanceTreeNode - Узел сбалансированного дерева \en BalanceTreeNode - Node of balanced tree // \ru BalanceTree - Сбалансированное дерево \en BalanceTree - Balanced tree // \ru BalanceTreeIterator - Класс итератора для сбалансированного дерева \en BalanceTreeIterator - Balanced tree iterator class // //////////////////////////////////////////////////////////////////////////////// #ifndef __BALANCETREE_H #define __BALANCETREE_H #include #include "templ_delete_define.h" #include "templ_three_states.h" #include "templ_s_array.h" template class BalanceTree; //----------------------------------------------------------------------------- // \ru сравниваем указатели \en compare pointers // --- template ThreeStates SimplePointCompFuncT( const Type * t1, const Type * t2 ) { return size_t(t1) == size_t(t2) ? ts_neutral : size_t(t1) < size_t(t2) ? ts_negative : ts_positive; } //----------------------------------------------------------------------------- // \ru сравниваем указатели \en compare pointers // --- template ThreeStates SimplePointCompFuncV( const Type * t1, const void * t2 ) { return size_t(t1) == size_t(t2) ? ts_neutral : size_t(t1) < size_t(t2) ? ts_negative : ts_positive; } FORVARD_DECL_TEMPLATE_TYPENAME( class BalanceTreeNode ); FORVARD_DECL_TEMPLATE_TYPENAME( void destroy_tree_node ( BalanceTreeNode &, DelType del ) ); //----------------------------------------------------------------------------- /** \brief \ru Узел сбалансированного дерева. \en Node of balanced tree. \~ \details \ru Узел сбалансированного дерева. \n \en Node of balanced tree. \n \~ \ingroup Base_Tools */ // --- template class BalanceTreeNode { public: BalanceTree & parent_m; ///< \ru Родитель узла. \en Parent of node. BalanceTreeNode * left_m; ///< \ru Левое поддерево. \en Left subtree. BalanceTreeNode * right_m; ///< \ru Правое поддерево. \en Right subtree. ThreeStates balance_m; ///< \ru Признак сбалансированности. \en Attribute of balance. Type * content_m; ///< \ru Указатель на элемент. \en Pointer to element. public: /// \ru Конструктор. \en Constructor. BalanceTreeNode( BalanceTree & parent, Type * content ); /// \ru Деструктор. \en Destructor. virtual ~BalanceTreeNode(); /// \ru Установить левую ветвь. \en Set left branch. void SetLeft ( BalanceTreeNode * p ); /// \ru Установить правую ветвь. \en Set right branch. void SetRight( BalanceTreeNode * p ); #ifdef __DEBUG_MEMORY_ALLOCATE_FREE_ public: void * operator new ( size_t ); void operator delete ( void *, size_t ); #endif // __DEBUG_MEMORY_ALLOCATE_FREE_ private: TEMPLATE_FRIEND void destroy_tree_node TEMPLATE_SUFFIX ( BalanceTreeNode &, DelType del ); void operator = ( const BalanceTreeNode & ); }; FORVARD_DECL_TEMPLATE_TYPENAME( class BalanceTree ); FORVARD_DECL_TEMPLATE_TYPENAME( Type * find_tree( const BalanceTree &, void * content, bool compT ) ); //----------------------------------------------------------------------------- /** \brief \ru Cбалансированное дерево. \en Balanced tree. \~ \details \ru Cбалансированное дерево. \n \en Balanced tree. \n \~ \ingroup Base_Tools */ // --- template class BalanceTree { public: BalanceTreeNode * root_m; ///< \ru Корень дерева. \en Root of tree. size_t allCount_m; ///< \ru Количество. \en Count. bool owns_m; ///< \ru Можно ли удалять элементы. \en Whether it is possible to delete elements. bool isBranchGrew_m; ///< \ru Флаг роста дерева. \en Flag of growth of a tree. public: typedef ThreeStates (*Compare_t)( const Type *, const Type * ); typedef ThreeStates (*Compare_v)( const Type *, const void * ); Compare_t compT_m; ///< \ru Функция сортировки используется при добавлении объекта. \en Sorting function is used while adding an object. Compare_v compV_m; ///< \ru Функция сортировки используется при поиске объекта. \en Sorting function is used while search an object. #ifdef C3D_DEBUG static size_t countIsSame; ///< \ru Число сравнений (для отладки) \en Count of comparisons (for debug) #endif // C3D_DEBUG public: /// \ru Конструктор. \en Constructor. BalanceTree( Compare_t c_t = SimplePointCompFuncT, Compare_v c_v = nullptr/*SimplePointCompFuncV*/, bool shouldDelete = true ); /// \ru Деструктор. \en Destructor. virtual ~BalanceTree(); public: bool Add ( Type * ); ///< \ru Добавить элемент. \en Add element. size_t Count () const { return allCount_m; } ///< \ru Получить количество элементов. \en Set count of elements. void Flush ( DelType = defDelete ); ///< \ru Удалить все элементы. \en Delete all elements. bool Remove ( Type * delObject, DelType = defDelete ); ///< \ru Удалить элемент из массива. \en Delete an element from array. bool FindIt ( const Type * ) const; ///< \ru Найти элемент по указателю. \en Find an element by a pointer Type * Find ( void * ) const; ///< \ru Найти элемент. \en Find an element. bool Detach ( const Type * ); ///< \ru Отсоединить объект. \en Detach an object. typedef void (*IterFunc) ( Type &, void *); void ForEach ( IterFunc f, void *pars ); // \ru НЕ классный итератор \en Iterator IS OUT OF a class protected: /// \ru Добавить объект в дерево. \en Add object to tree. bool AddToBalanceTree ( Type & content, BalanceTreeNode *& node, bool & isBranchGrew ); /// \ru Удалить объект из дерева. \en Delete an object from tree. bool DeleteFromBalanceTree( Type & content, BalanceTreeNode *& node, bool & isBranchGrew, DelType del ); /// \ru Балансировать левую ветвь. \en Balance left branch. void BalanceL ( BalanceTreeNode *& node, bool & isBranchGrew ); /// \ru Балансировать правую ветвь. \en Balance right branch. void BalanceR ( BalanceTreeNode *& node, bool & isBranchGrew ); // \ru Исключить из сбалансированного дерева. \en Exclude from balanced tree. bool DelFromBalanceTree ( BalanceTreeNode *& q, BalanceTreeNode *& r, bool & isBranchGrew ); private: void DoubleTurningRL ( BalanceTreeNode *& node, BalanceTreeNode * p1, BalanceTreeNode *& p2 ); void DoubleTurningLR ( BalanceTreeNode *& node, BalanceTreeNode * p1, BalanceTreeNode *& p2 ); #ifdef __DEBUG_MEMORY_ALLOCATE_FREE_ public: void * operator new ( size_t ); void operator delete ( void *, size_t ); #endif // __DEBUG_MEMORY_ALLOCATE_FREE_ private: TEMPLATE_FRIEND Type * find_tree TEMPLATE_SUFFIX ( const BalanceTree &, void * content, bool compT ); void for_each_in_tree( BalanceTreeNode &, typename BalanceTree::IterFunc f, void *pars ); // \ru неклассный \en out of class }; #ifdef __DEBUG_MEMORY_ALLOCATE_FREE_ //------------------------------------------------------------------------------ // \ru Перегрузка оператора new. \en Overloading of the "new" operator. // --- template inline void * BalanceTree::operator new( size_t size ) { return ::Allocate( size, typeid(BalanceTree).name() ); } //------------------------------------------------------------------------------ // \ru Перегрузка оператора delete. \en Overloading of the "delete" operator. // --- template inline void BalanceTree::operator delete ( void * ptr, size_t size ) { ::Free( ptr, size, typeid(BalanceTree).name() ); } #endif // __DEBUG_MEMORY_ALLOCATE_FREE_ //----------------------------------------------------------------------------- // \ru Узел \en Node // --- template class PPNode { public: /// \ru Типы движения по дереву. \en Types of moving in the tree. enum PPNodeType { iRoot = 0, // \ru текущий this \en current 'this' iLeft = 1, // \ru текущий Left \en current 'Left' iRight = 2, // \ru текущий Right \en current 'Right' iRemove = 3 // \ru удалять \en remove }; BalanceTreeNode * node_m; PPNodeType typeRAB_m; public: PPNode( BalanceTreeNode * node = nullptr, PPNodeType t = iRoot ) : node_m(node) , typeRAB_m(t) {} PPNode( PPNode & other ) : node_m( other.node) , typeRAB_m( other.typeRAB_m ) {} void Init( BalanceTreeNode * node, PPNodeType t ) { node_m = node; typeRAB_m = t; } }; //----------------------------------------------------------------------------- /** \brief \ru Итератор сбалансированного дерева. \en Iterator of balanced tree. \~ \details \ru Итератор сбалансированного дерева. \n \en Iterator of balanced tree. \n \~ \ingroup Base_Tools */ // --- template class BalanceTreeIterator { public: /// \ru Типы движения по дереву. \en Types of moving through the tree. enum IteratorType { /// \ru Умолчательный. \en Default. iDeforder = 0, /// \ru Сверху вниз R(корень), A(слева), B(справа). \en Top-down R(root), A(at the left), B(at the right). iPreorder = 1, /// \ru Слева направо A(слева), R(корень), B(справа) по возрастанию. \en From left to right A(at the left), R(root), B(at the right) in ascending order. iInorder = 2, /// \ru Снизу вверх A(слева), B(справа), R(корень). \en Bottom-up A(at the left), B(at the right), R(root). iPostorder = 3, /// \ru Справа налево B(справа), R(корень), A(слева) по убыванию. \en From right to left B(at the right), R(root), A(at the left) in descending order. iBackorder = 4 //-V112 }; protected: BalanceTree & m_tree; ///< \ru Дерево, по которому движемся. \en Tree to move through. IteratorType m_iterType; ///< \ru Тип движения. \en Type of move. SArray< PPNode > m_PPNodes; ///< \ru Последовательный список узлов итератора(имитация рекурсии). \en Sequential list of iterator nodes (imitation of recursion). PPNode m_PPNode; ///< \ru Для наполнения. \en For filling. BalanceTreeNode * m_CurNode; ///< \ru Текущий узел. \en Current node. public: BalanceTreeIterator( BalanceTree & tree, IteratorType t = iPreorder ) : m_tree ( tree ) , m_iterType( t ) , m_PPNodes ( 0x100, 0x100 ) , m_PPNode ( ) { Restart( m_iterType ); } virtual ~BalanceTreeIterator() {} public: Type * operator ++ (int); virtual operator Type * () const; virtual void Restart( IteratorType t = iDeforder ); // \ru КВН K8+ Будет работать правильно, если делать Restart. Чтобы работало в цикле, нужно набирать \en КВН K8+ Will correctly work if doing Restart. For working in cycle it is necessary to gather // \ru КВН K8+ удаляемые объекты в список и удалять в конце цикла или по Restart \en КВН K8+ deleted objects to list and remove it at the end of cycle or by Restart // \ru КВН K8+ bool Remove ( DelType = defDelete ); // удалить элемент списка и продвинуть вперед \en КВН K8+ bool Remove ( DelType = defDelete ); // remove element from list and move ahead // \ru КВН K8+ bool Detach (); // отсоединить элемент списка \en КВН K8+ bool Detach (); // detach element of list protected: void Iterate ( BalanceTreeNode * node ); typename PPNode::PPNodeType GetNodeType ( bool add, typename PPNode::PPNodeType oldTypeRAB ); private: void operator = ( const BalanceTreeIterator & ); }; //------------------------------------------------------------------------------ // //--- #ifdef C3D_DEBUG template size_t BalanceTree::countIsSame = 0; #endif // C3D_DEBUG //////////////////////////////////////////////////////////////////////////////// // // \ru BalanceTreeNode - узел сбалансированного дерева \en BalanceTreeNode - node of balanced tree // //////////////////////////////////////////////////////////////////////////////// #ifdef __DEBUG_MEMORY_ALLOCATE_FREE_ //------------------------------------------------------------------------------ // \ru Перегрузка оператора new. \en Overloading of the "new" operator. // --- template inline void * BalanceTreeNode::operator new( size_t size ) { return ::Allocate( size, typeid(BalanceTreeNode).name() ); } //------------------------------------------------------------------------------ // \ru Перегрузка оператора delete. \en Overloading of the "delete" operator. // --- template inline void BalanceTreeNode::operator delete ( void * ptr, size_t size ) { ::Free( ptr, size, typeid(BalanceTreeNode).name() ); } #endif // __DEBUG_MEMORY_ALLOCATE_FREE_ //------------------------------------------------------------------------------- // \ru конструктор узла дерева \en constructor of node of tree // --- template inline BalanceTreeNode::BalanceTreeNode( BalanceTree & parent, Type * content ) : parent_m ( parent ), left_m ( nullptr ), right_m ( nullptr ), // \ru КВН K8+ count_m ( 0 ), \en КВН K8+ count_m ( 0 ), balance_m ( ts_neutral ), content_m ( content ) { } //------------------------------------------------------------------------------ // \ru деструктор узла дерева \en destructor of node of tree // --- template inline BalanceTreeNode::~BalanceTreeNode() { destroy_tree_node( *this, defDelete ); } //----------------------------------------------------------------------------- // // --- template inline void BalanceTreeNode::SetLeft ( BalanceTreeNode * p ){ left_m = p; } //----------------------------------------------------------------------------- // // --- template inline void BalanceTreeNode::SetRight( BalanceTreeNode * p ){ right_m = p; } //////////////////////////////////////////////////////////////////////////////// // // \ru BalanceTree - сбалансированное дерево \en BalanceTree - balanced tree // //////////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------- // \ru конструктор дерева \en constructor of tree // --- template inline BalanceTree::BalanceTree( Compare_t c_t, Compare_v c_v, bool shouldDelete ) : root_m ( nullptr ), allCount_m ( 0 ), owns_m ( shouldDelete ), isBranchGrew_m( false ), compT_m ( c_t ), compV_m ( c_v ) { if ( !compV_m && compT_m == (Compare_t) SimplePointCompFuncT ) compV_m = SimplePointCompFuncV; #ifdef C3D_DEBUG countIsSame = 0; #endif // C3D_DEBUG } //------------------------------------------------------------------------------ // \ru деструктор дерева \en destructor of tree // --- template inline BalanceTree::~BalanceTree() { delete root_m; } //------------------------------------------------------------------------------ // \ru добавить 1 элемент в конец массива \en add 1 element at the end of array // --- template inline bool BalanceTree::Add( Type * ent ) { #ifdef C3D_DEBUG countIsSame = 0; #endif // C3D_DEBUG bool res = false; if ( ent && compT_m ) { res = AddToBalanceTree( *ent, root_m, isBranchGrew_m ); } return res; } //------------------------------------------------------------------------------ // \ru обнулить количество элементов \en set to null the count of elements // --- template inline void BalanceTree::Flush( DelType del ) { if( root_m ) { destroy_tree_node( *root_m, del ); delete root_m; root_m = nullptr; } allCount_m = 0; isBranchGrew_m = false; } //----------------------------------------------------------------------------- // \ru удалить элемент из массива \en delete an element from array // --- template inline bool BalanceTree::Remove( Type * delObject, DelType del ) { #ifdef C3D_DEBUG countIsSame = 0; #endif // C3D_DEBUG bool res = false; if ( delObject && compT_m ) res = DeleteFromBalanceTree( *delObject, root_m, isBranchGrew_m, del ); return res; } //----------------------------------------------------------------------------- // \ru отсоединить объект \en detach an object // --- template inline bool BalanceTree::Detach( const Type *d ){ return Remove( (Type*)d, noDelete ); } //----------------------------------------------------------------------------- // \ru найти элемент по указателю \en find an element by a pointer // --- template inline bool BalanceTree::FindIt ( const Type * content ) const { #ifdef C3D_DEBUG countIsSame = 0; #endif // C3D_DEBUG Type * t = compT_m ? find_tree( *this, (void *)content, true/*compT*/ ) : nullptr; return !!t; } //----------------------------------------------------------------------------- // \ru найти элемент \en find an element // --- template inline Type * BalanceTree::Find ( void * content ) const { #ifdef C3D_DEBUG countIsSame = 0; #endif // C3D_DEBUG return compV_m ? find_tree( *this, content, false/*compT*/ ) : nullptr; } //------------------------------------------------------------------------------ // \ru не классный \en out of class // --- template inline void BalanceTree::for_each_in_tree( BalanceTreeNode& node, typename BalanceTree::IterFunc f, void *pars ) { if ( node.left_m ) for_each_in_tree( *node.left_m, f, pars ); PRECONDITION( f ); (*f)( *node.content_m, pars ); if ( node.right_m ) for_each_in_tree( *node.right_m, f, pars ); } //------------------------------------------------------------------------------ // \ru не классный \en out of class // --- template inline void BalanceTree::ForEach( IterFunc f, void *pars ) { if ( root_m && f ) for_each_in_tree( *root_m, f, pars ); } //----------------------------------------------------------------------------- // \ru двойной RL-поворот \en double RL-rotation // --- template inline void BalanceTree::DoubleTurningRL ( BalanceTreeNode *& node, BalanceTreeNode * p1, BalanceTreeNode *& p2 ) { p2 = p1->left_m; if ( p2 ) { p1 ->SetLeft( p2->right_m ); p2 ->SetRight( p1 ); node->SetRight( p2->left_m ); p2 ->SetLeft( node ); node->balance_m = ( p2->balance_m == ts_positive ) ? ts_negative : ts_neutral; p1->balance_m = ( p2->balance_m == ts_negative ) ? ts_positive : ts_neutral; node = p2; } } //----------------------------------------------------------------------------- // \ru двойной LR-поворот \en double LR-rotation // --- template inline void BalanceTree::DoubleTurningLR ( BalanceTreeNode *& node, BalanceTreeNode * p1, BalanceTreeNode *& p2 ) { p2 = p1->right_m; if ( p2 ) { p1 ->SetRight( p2->left_m ); p2 ->SetLeft( p1 ); node->SetLeft( p2->right_m ); p2 ->SetRight( node ); node->balance_m = ( p2->balance_m == ts_negative ) ? ts_positive : ts_neutral; p1->balance_m = ( p2->balance_m == ts_positive ) ? ts_negative : ts_neutral; node = p2; } } //----------------------------------------------------------------------------- // \ru Построение идеально сбалансированного дерева \en Creation of ideally balanced tree // --- template inline bool BalanceTree::AddToBalanceTree( Type & content, BalanceTreeNode *& node, bool & isBranchGrew ) { bool isAdd = false; if ( !node ) { node = new BalanceTreeNode( *this, &content ); isAdd = true; isBranchGrew = true; allCount_m++; // \ru подсчитываем общее кол-во узлов \en compute the total count of nodes } else { ThreeStates compRres = compT_m( (Type*)node->content_m, (Type*)&content ); #ifdef C3D_DEBUG countIsSame++; #endif // C3D_DEBUG if ( compRres != ts_neutral ) { if ( compRres == ts_positive ) { isAdd = AddToBalanceTree( content, node->left_m, isBranchGrew ); // \ru выросла левая ветвь \en left branch is grew up. if ( isAdd && isBranchGrew ) { switch ( node->balance_m ) { case ts_positive : node->balance_m = ts_neutral; isBranchGrew = false; break; case ts_neutral : node->balance_m = ts_negative; break; // \ru балансировка \en balancing case ts_negative : { BalanceTreeNode * p1 = nullptr; BalanceTreeNode * p2 = nullptr; p1 = node->left_m; if ( p1 ){ if ( p1->balance_m == ts_negative ) { // \ru однократный LL поворот \en single LL rotation node->SetLeft( p1->right_m ); p1->SetRight( node ); node->balance_m = ts_neutral; node = p1; } // \ru двойной LR-поворот \en double LR-rotation else { DoubleTurningLR( node, p1, p2 ); } } node->balance_m = ts_neutral; isBranchGrew = false; } break; } } } else { isAdd = AddToBalanceTree( content, node->right_m, isBranchGrew ); if ( isAdd && isBranchGrew ) { switch ( node->balance_m ) { case ts_negative : node->balance_m = ts_neutral; isBranchGrew = false; break; case ts_neutral : node->balance_m = ts_positive; break; // \ru балансировка \en balancing case ts_positive : { BalanceTreeNode * p1 = nullptr; BalanceTreeNode * p2 = nullptr; p1 = node->right_m; if ( p1 ) { if ( p1->balance_m == ts_positive ) { // \ru однократный RR поворот \en single RR rotation node->SetRight( p1->left_m ); p1->SetLeft( node ); node->balance_m = ts_neutral; node = p1; } else { // \ru двойной RL-поворот \en double RL-rotation DoubleTurningRL( node, p1, p2 ); } } node->balance_m = ts_neutral; isBranchGrew = false; } break; } } } } } return isAdd; } //----------------------------------------------------------------------------- // \ru Балансировка слева \en Balancing at the left // --- template inline void BalanceTree::BalanceL( BalanceTreeNode *& node, bool & isBranchGrew ) { switch ( node->balance_m ) { case ts_negative : node->balance_m = ts_neutral; break; case ts_neutral : node->balance_m = ts_positive; isBranchGrew = false; break; // \ru балансировка \en balancing case ts_positive : { BalanceTreeNode * p1 = nullptr; BalanceTreeNode * p2 = nullptr; p1 = node->right_m; if ( p1 ) { if ( p1->balance_m >= ts_neutral ) { // \ru однократный RR поворот \en single RR rotation node->SetRight( p1->left_m ); p1->SetLeft( node ); if ( p1->balance_m == ts_neutral ) { node->balance_m = ts_positive; p1->balance_m = ts_negative; isBranchGrew = false; } else { node->balance_m = ts_neutral; p1->balance_m = ts_neutral; } node = p1; } else { // \ru двойной RL-поворот \en double RL-rotation DoubleTurningRL( node, p1, p2 ); if( p2 ) p2->balance_m = ts_neutral; } } } break; } } //----------------------------------------------------------------------------- // \ru Балансировка справа \en Balancing at the right // --- template inline void BalanceTree::BalanceR( BalanceTreeNode *& node, bool & isBranchGrew ) { switch ( node->balance_m ) { case ts_positive : node->balance_m = ts_neutral; break; case ts_neutral : node->balance_m = ts_negative; isBranchGrew = false; break; // \ru балансировка \en balancing case ts_negative : { BalanceTreeNode * p1 = nullptr; BalanceTreeNode * p2 = nullptr; p1 = node->left_m; if ( p1 ) { if ( p1->balance_m <= ts_neutral ) { // \ru однократный LL поворот \en single LL rotation node->SetLeft( p1->right_m ); p1->SetRight( node ); if ( p1->balance_m == ts_neutral ) { node->balance_m = ts_negative; p1->balance_m = ts_positive; isBranchGrew = false; } else { node->balance_m = ts_neutral; p1->balance_m = ts_neutral; } node = p1; } else { // \ru двойной LR-поворот \en double LR-rotation DoubleTurningLR( node, p1, p2 ); if( p2 ) p2->balance_m = ts_neutral; } } } break; } } //----------------------------------------------------------------------------- // \ru Исключение из сбалансированного дерева \en Exclude from balanced tree // --- template inline bool BalanceTree::DelFromBalanceTree( BalanceTreeNode *& q, BalanceTreeNode *& r, bool & isBranchGrew ) { bool res = false; if ( r->right_m ) { res = DelFromBalanceTree( q, r->right_m, isBranchGrew ); if ( res && isBranchGrew ) BalanceR( r, isBranchGrew ); } else { Type * content = q->content_m; q->content_m = r->content_m; r->content_m = content; // \ru КВН K8+ q->count_m = r->count_m; \en КВН K8+ q->count_m = r->count_m; q = r; r = r->left_m; isBranchGrew = true; } return res; } //----------------------------------------------------------------------------- // \ru Исключение из сбалансированного дерева \en Exclude from balanced tree // --- template inline bool BalanceTree::DeleteFromBalanceTree( Type & content, BalanceTreeNode *& node, bool & isBranchGrew, DelType del ) { bool res = false; if ( node && node->content_m ) { ThreeStates compRres = compT_m( (Type*)node->content_m, (Type*)&content ); #ifdef C3D_DEBUG countIsSame++; #endif // C3D_DEBUG switch ( compRres ) { case ts_positive : { res = DeleteFromBalanceTree( content, node->left_m, isBranchGrew, del ); if ( res && isBranchGrew ) BalanceL( node, isBranchGrew ); break; } case ts_negative : { res = DeleteFromBalanceTree( content, node->right_m, isBranchGrew, del ); if ( res && isBranchGrew ) BalanceR( node, isBranchGrew ); break; } case ts_neutral : { // \ru исключение node \en exclude node BalanceTreeNode * q = node; if ( !q->right_m ) { node = q->left_m; isBranchGrew = true; } else if ( !q->left_m ) { node = q->right_m; isBranchGrew = true; } else { // \ru удаляемый узел имеет двух потомков. В этом случае нужно "спуститься" вдоль правой ветви \en deleted node has two descendants. In this case it is necessary to "go down" through right branch // \ru левого поддерева, найти самый правый узел-лист. Перенести информацию из него в node, \en of left subtree and find most right leaf node. Transfer information from it to node, // \ru информацию из node в этот лист( content ). Переуказать q на этот лист, чтобы удалить узел-лист. \en transfer information from node to this leaf ( content ). Re-point q to this leaf to delete the leaf node. res = DelFromBalanceTree( q, q->left_m, isBranchGrew ); if ( res && isBranchGrew ) BalanceL( node, isBranchGrew ); } bool oldowns = owns_m; owns_m = del == Delete ? true : del == noDelete ? false : owns_m; q->left_m = nullptr; q->right_m = nullptr; delete q; owns_m = oldowns; allCount_m--; // \ru подсчитываем общее кол-во узлов \en compute the total count of nodes res = true; break; } } } return res; } //------------------------------------------------------------------------------- // \ru удаление всех указателей, собранных в поддереве \en delete all pointers collected in subtree // --- template void destroy_tree_node( BalanceTreeNode& treeNode, DelType del ) { delete treeNode.left_m; treeNode.left_m = nullptr; delete treeNode.right_m; treeNode.right_m = nullptr; bool shouldDelete = del == Delete || ( del == defDelete && treeNode.parent_m.owns_m ); if ( shouldDelete ) { delete treeNode.content_m; treeNode.content_m = nullptr; } } //----------------------------------------------------------------------------- // \ru найти элемент по указателю \en find an element by a pointer // --- template Type * find_tree( const BalanceTree& tree, void * content, bool compT ) { Type * res = nullptr; const BalanceTreeNode * node = tree.root_m; if ( node ) { ThreeStates compRres = ts_negative; while ( node && compRres != ts_neutral ) { if ( compT ) compRres = tree.compT_m( (Type*)node->content_m, (Type*)content ); else compRres = tree.compV_m( (Type*)node->content_m, content ); #ifdef C3D_DEBUG BalanceTree::countIsSame++; #endif // C3D_DEBUG switch ( compRres ) { case ts_negative : node = node->right_m; break; case ts_positive : node = node->left_m; break; case ts_neutral : res = node->content_m; break; } } } return res; } //////////////////////////////////////////////////////////////////////////////// // // \ru BalanceTreeIterator - класс итератора для сбалансированного дерева \en BalanceTreeIterator - balanced tree iterator class // //////////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- // // --- template inline void BalanceTreeIterator::Restart( IteratorType t ) { if ( t ) m_iterType = t; m_PPNodes.Flush(); m_CurNode = m_tree.root_m; if ( m_CurNode ) Iterate( m_CurNode ); } //----------------------------------------------------------------------------- // \ru взять и сместиться \en displace // --- template inline Type * BalanceTreeIterator::operator ++(int) { Type * res = m_CurNode ? m_CurNode->content_m : nullptr; if ( m_CurNode ) Iterate( m_CurNode ); return res; } //----------------------------------------------------------------------------- // \ru приведение \en conversion // --- template inline BalanceTreeIterator::operator Type * () const { return m_CurNode ? m_CurNode->content_m : nullptr; } //----------------------------------------------------------------------------- // \ru сверху вниз R(корень), A(слева), B(справа) \en top-down R(root), A(at the left), B(at the right) // \ru слева на право A(слева), R(корень), B(справа) по возрастанию \en from left to right A(at the left), R(root), B(at the right) in ascending order // \ru снизу вверх A(слева), B(справа), R(корень) \en bottom-up A(at the left), B(at the right), R(root) // \ru справа на лево B(справа), R(корень), A(слева) по убыванию \en from right to left B(at the right), R(root), A(at the left) in descending order // --- template inline typename PPNode::PPNodeType BalanceTreeIterator::GetNodeType( bool add, typename PPNode::PPNodeType oldTypeRAB ) { typename PPNode::PPNodeType res = PPNode::iRoot; if ( add ) { // \ru при добавлении в список \en at addition to list switch ( m_iterType ) { case iPreorder : res = PPNode::iRoot; break; // \ru сверху вниз R(корень), A(слева), B(справа) \en top-down R(root), A(at the left), B(at the right) case iPostorder : // \ru снизу вверх A(слева), B(справа), R(корень) \en bottom-up A(at the left), B(at the right), R(root) case iInorder : res = PPNode::iLeft; break; // \ru слева на право A(слева), R(корень), B(справа) по возрастанию \en from left to right A(at the left), R(root), B(at the right) in ascending order case iBackorder : res = PPNode::iRight; break; // \ru справа на лево B(справа), R(корень), A(слева) по убыванию \en from right to left B(at the right), R(root), A(at the left) in descending order default: break; } } else { switch ( m_iterType ) { case iPreorder : { // \ru сверху вниз R(корень), A(слева), B(справа) \en top-down R(root), A(at the left), B(at the right) switch ( oldTypeRAB ) { case PPNode::iRoot : res = PPNode::iLeft; break; case PPNode::iLeft : res = PPNode::iRight; break; case PPNode::iRight: res = PPNode::iRemove; break; default: break; } break; } case iPostorder : { // \ru снизу вверх A(слева), B(справа), R(корень) \en bottom-up A(at the left), B(at the right), R(root) switch ( oldTypeRAB ) { case PPNode::iLeft : res = PPNode::iRight; break; case PPNode::iRight: res = PPNode::iRoot; break; case PPNode::iRoot : res = PPNode::iRemove; break; default: break; } break; } case iInorder : { // \ru слева на право A(слева), R(корень), B(справа) по возрастанию \en from left to right A(at the left), R(root), B(at the right) in ascending order switch ( oldTypeRAB ) { case PPNode::iLeft : res = PPNode::iRoot; break; case PPNode::iRoot : res = PPNode::iRight; break; case PPNode::iRight: res = PPNode::iRemove; break; default: break; } break; } case iBackorder : { // \ru справа на лево B(справа), R(корень), A(слева) по убыванию \en from right to left B(at the right), R(root), A(at the left) in descending order switch ( oldTypeRAB ) { case PPNode::iRight: res = PPNode::iRoot; break; case PPNode::iRoot : res = PPNode::iLeft; break; case PPNode::iLeft : res = PPNode::iRemove; break; default: break; } break; } default: break; } } return res; } //----------------------------------------------------------------------------- // \ru Продвинуться. \en Move ahead. // \ru сверху вниз R(корень), A(слева), B(справа) \en top-down R(root), A(at the left), B(at the right) // \ru слева на право A(слева), R(корень), B(справа) по возрастанию \en from left to right A(at the left), R(root), B(at the right) in ascending order // \ru снизу вверх A(слева), B(справа), R(корень) \en bottom-up A(at the left), B(at the right), R(root) // \ru справа на лево B(справа), R(корень), A(слева) по убыванию \en from right to left B(at the right), R(root), A(at the left) in descending order // --- template inline void BalanceTreeIterator::Iterate( BalanceTreeNode * node ) { if ( node ) { ptrdiff_t /*OV_x64 int*/index = m_PPNodes.MaxIndex(); if ( index < 0 || m_PPNodes[index].node_m != node ) { m_PPNode.Init( node, GetNodeType(true, PPNode::iRoot) ); m_PPNodes.Add( m_PPNode ); index = m_PPNodes.MaxIndex(); } bool fRepeat = true; while ( fRepeat ) { switch ( m_PPNodes[index].typeRAB_m ) { case PPNode::iRoot : { m_CurNode = node; m_PPNodes[index].typeRAB_m = GetNodeType( false/*add*/, m_PPNodes[index].typeRAB_m ); fRepeat = false; break; } case PPNode::iLeft : { if ( node->left_m ) { Iterate( node->left_m ); fRepeat = false; } m_PPNodes[index].typeRAB_m = GetNodeType( false/*add*/, m_PPNodes[index].typeRAB_m ); break; } case PPNode::iRight : { if ( node->right_m ) { Iterate( node->right_m ); fRepeat = false; } m_PPNodes[index].typeRAB_m = GetNodeType( false/*add*/, m_PPNodes[index].typeRAB_m ); break; } case PPNode::iRemove : { index = m_PPNodes.MaxIndex(); if ( index >= 0 ) { m_PPNodes.RemoveInd( index-- ); if ( index >= 0 ) { m_CurNode = m_PPNodes[index].node_m; if ( m_CurNode ) Iterate( m_CurNode ); } else m_CurNode = nullptr; } else m_CurNode = nullptr; fRepeat = false; break; } } } } } #endif // __BALANCETREE_H