//////////////////////////////////////////////////////////////////////////////// /** \file \brief \ru Упорядоченный одномерный массив объектов. \en Ordered one-dimensional array of objects. \~ */ //////////////////////////////////////////////////////////////////////////////// #ifndef __TEMPL_CSS_ARRAY_H #define __TEMPL_CSS_ARRAY_H #include #include FORVARD_DECL_TEMPLATE_TYPENAME( class CSSArray ); FORVARD_DECL_TEMPLATE_TYPENAME( void q_sort( CSSArray & arr, SArray * del ) ); FORVARD_DECL_TEMPLATE_TYPENAME( reader & CALL_DECLARATION operator >> ( reader & in, CSSArray & ref ) ); FORVARD_DECL_TEMPLATE_TYPENAME( writer & CALL_DECLARATION operator << ( writer & out, const CSSArray & ref ) ); //------------------------------------------------------------------------------ /** \brief \ru Упорядоченный одномерный массив. \en Ordered one-dimensional array. \~ \details \ru Упорядоченный одномерный массив объектов. \n У объектов массива должны быть операторы "==" и "<". Имеется возможность добавлять несортированные данные через функцию AddNoSort, но при первом обращении к функциям Add и Find произойдет сортировка Одинаковые объекты не добавляются. \en Ordered one-dimensional array of objects. \n Elements of the array should have operators "==" and "<". The unsorted data can be added by the function 'AddNoSort', but the sorting starts after the first call of functions Add and Find. The similar objects are not added. \~ \ingroup Base_Tools_Containers */ // --- template class CSSArray : protected SSArray { bool m_sort; ///< \ru Признак сортированности массива. \en Attribute of an array being sorted. public: /// \ru Конструктор. \en Constructor. CSSArray( size_t maxCnt = 0, uint16 delt = 1 ) : SSArray( maxCnt, delt ) , m_sort( true ) {} /// \ru Конструктор копирования. \en Copy constructor. CSSArray( const CSSArray & other ) : SSArray( other ) , m_sort( other.m_sort ) {} /// \ru Конструктор копирования. \en Copy constructor. CSSArray( const SArray & other, SArray * del = nullptr ) : SSArray( other ) , m_sort( false ) { q_sort( *this, del ); } /// \ru Конструктор копирования. \en Copy constructor. CSSArray( const SArray< std::pair > & other, bool addFirst, SArray * del = nullptr ) : SSArray( other.Count(), 1 ) , m_sort( false ) { if ( addFirst ) { for ( size_t k = 0, cnt = other.Count(); k < cnt; k++ ) AddNoSort( other[k].first ); } else { for ( size_t k = 0, cnt = other.Count(); k < cnt; k++ ) AddNoSort( other[k].second ); } q_sort( *this, del ); } using SSArray::Flush; using SSArray::HardFlush; using SSArray::Adjust; using SSArray::operator[]; using SSArray::Remove; using SSArray::RemoveInd; using SSArray::Count; using SSArray::MaxIndex; using SSArray::GetAddr; using SSArray::GetEndAddr; using SSArray::Reserve; using SSArray::SetSize; using SSArray::SetMaxDelta; using SSArray::empty; using SSArray::size; using SSArray::reserve; using SSArray::capacity; using SSArray::front; using SSArray::back; using SSArray::clear; using SSArray::begin; using SSArray::end; void AddNoSort( const Type & ent ) { SSArray::AddSimple( ent ); m_sort = false; } ///< \ru Добавить элемент без сортировки. \en Add element without sorting. Type * Add ( const Type & ); ///< \ru Добавить элемент с упорядочиванием по массиву. \en Add element with sorting. Type * Add ( const Type &, size_t & indexEnt ); ///< \ru Добавить элемент с упорядочиванием по массиву, возвращает индекс. \en Add element with sorting by array, returns index of the element. size_t Find( const Type & ); ///< \ru Найти элемент в упорядоченном массиве. \en Find an element in ordered array. void Sort( SArray * del = nullptr ); ///< \ru Выполнить сортировку элементов массива. \en Sort elements of array. size_t RemoveObj( const Type & delObject ); ///< \ru Удалить элемент из массива. \en Delete an element from array. void SetNoSort() { m_sort = false; } ///< \ru Сбросить флаг сортированности. \en Reset the flag of being sorted. void AddArray( const CSSArray & arr, bool doSort ); ///< \ru Добавить массив. \en Add array void AddArray( const SArray & arr, bool doSort ); ///< \ru Добавить массив. \en Add array bool IsSorted() const {return m_sort; } ///< \ru Вернуть вризнак сортированности массива. \en Return an attribute of an array being sorted. TEMPLATE_FRIEND void q_sort TEMPLATE_SUFFIX ( CSSArray & arr, SArray * del ); TEMPLATE_FRIEND reader & CALL_DECLARATION operator >> TEMPLATE_SUFFIX ( reader & in, CSSArray & ref ); TEMPLATE_FRIEND writer & CALL_DECLARATION operator << TEMPLATE_SUFFIX ( writer & out, const CSSArray & ref ); // Intel Compiler 12 // KNOWN_OBJECTS_RW_REF_OPERATORS( CSSArray ) }; //------------------------------------------------------------------------------- // \ru добавление объекта в массив \en adding an object to array // --- template inline Type * CSSArray::Add( const Type & el ) { q_sort( *this, (SArray *)nullptr ); return SSArray::Add( el ); } //------------------------------------------------------------------------------- // \ru добавление объекта в массив \en adding an object to array // --- template inline Type * CSSArray::Add( const Type & el, size_t & indexEl ) { q_sort( *this, (SArray *)nullptr ); return SSArray::Add( el, indexEl ); } //------------------------------------------------------------------------------- // \ru добавление массива \en adding of an array // --- template inline void CSSArray::AddArray( const CSSArray & arr, bool doSort ) { if ( this != &arr ) { m_sort = false; (*this) += arr; if ( doSort ) q_sort( *this, (SArray *)nullptr ); } } //------------------------------------------------------------------------------- // \ru добавление массива \en adding of an array // --- template inline void CSSArray::AddArray( const SArray & arr, bool doSort ) { if ( this != &arr ) { m_sort = false; (*this) += arr; if ( doSort ) q_sort( *this, (SArray *)nullptr ); } } //------------------------------------------------------------------------------- // \ru поиск объекта в массиве \en search of an element in array // --- template inline size_t CSSArray::Find( const Type & el ) { q_sort( *this, (SArray *)nullptr ); return SSArray::Find( el ); } //------------------------------------------------------------------------------ // // --- template inline void CSSArray::Sort( SArray * del ) { q_sort( *this, del ); } //------------------------------------------------------------------------------ // \ru удалить элемент из массива \en delete an element from array // --- template inline size_t CSSArray::RemoveObj( const Type & delObject ) { size_t ind = Find( delObject ); if ( ind != SYS_MAX_T ) RemoveInd( ind ); return ind; } //----------------------------------------------------------------------------- // \ru Н.Вирт "Алгоритмы и структуры данных" 2е издание, Санкт-Петербург, 2001г., стр.111 \en see N.Wirth "Algorithms and Data Structures" // --- template void q_sort_r( CSSArray & arr, size_t minInd = SYS_MAX_T, size_t maxInd = SYS_MAX_T ) { if ( arr.Count() > 1 ) { if ( minInd == SYS_MAX_T ) minInd = 0; if ( maxInd == SYS_MAX_T || maxInd > (size_t)arr.MaxIndex() ) maxInd = (size_t)arr.MaxIndex(); // \ru проверено count > 0 \en chacked that count > 0 size_t i = minInd, j = maxInd; // \ru OV_x64 приводить к знаковому значению будем только в операторах > и < \en OV_x64 cast to signed value only in operators > and < size_t im = (i + j)/2; // \ru OV_x64 приводить к знаковому значению будем только в операторах > и < \en OV_x64 cast to signed value only in operators > and < Type * middle = (Type *)new char[sizeof(Type)]; ::memcpy( middle, &arr[im], sizeof( Type ) ); Type * buff = (Type *)new char[sizeof(Type)]; do { while( arr[i] < *middle ) i++; while( *middle < arr[j] ) j--; if ( (ptrdiff_t)i <= (ptrdiff_t)j ) { if ( i != j ) { Type * wi = &arr[i]; Type * wj = &arr[j]; ::memcpy( buff, wi, sizeof( Type ) ); ::memcpy( wi, wj, sizeof( Type ) ); ::memcpy( wj, buff, sizeof( Type ) ); } i++; j--; } } while( !((ptrdiff_t)i > (ptrdiff_t)j) ); delete [] (char*)buff; delete [] (char*)middle; if ( (ptrdiff_t)minInd < (ptrdiff_t)j ) q_sort_r( arr, minInd, j ); if ( (ptrdiff_t)i < (ptrdiff_t)maxInd ) q_sort_r( arr, i, maxInd ); } } //----------------------------------------------------------------------------- // \ru Аналог q_sort_r без рекурсии. Не требует выделения/освобождения памяти на каждой итерации. // \en Analog of q_sort_r without recursion. Not require memory allocation/deallocation at each iteration. // \param arr[out] - \ru Указатель на начало сортируемого участка массива. \en Pointer to the beginning of the array part being sorted. // \param minIndex[in] - \ru Индекс первого элемента в сортируемом участке массива. \en Index of the first element in the array part being sorted. // \param maxIndex[in] - \ru Индекс последнего элемента в сортируемом участке массива. \en Index of the last element in the array part being sorted. // --- template void q_sort_r2( Type * arr, size_t minIndex, size_t maxIndex ) { ptrdiff_t rangeSize = (ptrdiff_t)maxIndex - (ptrdiff_t)minIndex; if ( rangeSize == 1 ) { if ( arr[maxIndex] < arr[minIndex] ) { Type * buff = ( Type * )new char[sizeof( Type )]; Type * w0 = &arr[minIndex]; Type * w1 = &arr[maxIndex]; ::memcpy( buff, w1, sizeof( Type ) ); ::memcpy( w1, w0, sizeof( Type ) ); ::memcpy( w0, buff, sizeof( Type ) ); delete[]( char* )buff; } } else if ( rangeSize > 1 ) { c3d::NumbersPair iterStack[30]; int stackCount = -1; ptrdiff_t minInd = minIndex, maxInd = maxIndex; ptrdiff_t i = minInd, j = maxInd; ptrdiff_t im = 0; Type * middle = ( Type * )new char[sizeof( Type )]; Type * buff = ( Type * )new char[sizeof( Type )]; for ( ;; ) { i = minInd, j = maxInd; im = ( i + j ) / 2; ::memcpy( middle, &arr[im], sizeof( Type ) ); do { while ( arr[i] < *middle ) i++; while ( *middle < arr[j] ) j--; if ( i <= j ) { if ( i != j ) { Type * wi = &arr[i]; Type * wj = &arr[j]; ::memcpy( buff, wi, sizeof( Type ) ); ::memcpy( wi, wj, sizeof( Type ) ); ::memcpy( wj, buff, sizeof( Type ) ); } i++; j--; } } while ( !( i > j ) ); if ( j - minInd > maxInd - i ) { if ( minInd < j ) { iterStack[++stackCount].first = minInd; iterStack[stackCount].second = j; } if ( i < maxInd ) { minInd = i; continue; } } else { if ( i < maxInd ) { iterStack[++stackCount].first = i; iterStack[stackCount].second = maxInd; } if ( minInd < j ) { maxInd = j; continue; } } if ( stackCount < 0 ) break; // \ru Все подмассивы обработаны. \en All subarrays are done. minInd = iterStack[stackCount].first; maxInd = iterStack[stackCount--].second; } delete[]( char* )buff; delete[]( char* )middle; } } //----------------------------------------------------------------------------- // // --- template void q_sort( CSSArray & arr, SArray * del ) { if ( !arr.m_sort ) { if ( arr.Count() ) { q_sort_r2( arr.begin(), 0, arr.Count() - 1 ); // C3D-1211 //q_sort_r( arr ); // \ru удаление одинаковых \en deletion of similar objects for ( ptrdiff_t i = arr.MaxIndex(); i >= 1; i-- ) { // OV_x64 maxIndex >= 0 if ( arr[i] == arr[i-1] ) { if ( del ) del->Add( arr[i] ); arr.RemoveInd( i ); } } } arr.m_sort = true; } } #endif // __TEMPL_CSS_ARRAY_H