动态数组
总体表述
开发过程,经常需要对数据集合进行维护。
维护数据结合的数据结构可统称为容器。
动态数组是维护数据集合的容器的一种,
具备数组操作简单的特点,但允许集合内元素的动态增加和删除。
接口设计
template<typename T>
class DynArray
{
public:
DynArray();
DynArray(int nInitialSize_, const T& nInitialValue_);
~DynArray();
void Add(const T& value_);
void AddRange(const DynArray& arrItems_);
void Insert(int nIndex_, const T& value_);
void DeleteByIndex(int nIndex_ = -1);
void DeleteByValue(const T& value_);
void DeleteAll();
bool SetValue(int nIndex_, const T& value_);
bool GetValue(int nIndex_, T& value_) const;
int GetSize() const;
int GetCapacity() const;
int Find(std::function<bool(const T&)> fun_) const;
T& operator[](int nIndex_);
const T& operator[](int nIndex_) const;
DynArray(const DynArray<T>& arrElements_);
DynArray<T>& operator=(const DynArray<T>& arrElements_);
DynArray Sort(std::function<int(const T&, const T&)> fun_) const;
void Sort(std::function<int(const T&, const T&)> fun_);
void Reset();
private:
void Check(int nSize_);
void Shrink();
private:
T* m_pSource;// 当T为引用类型时,sizeof无法获得其真实大小
int m_nSize;
int m_nCapacity;
std::allocator<T> m_alloc;
};
实现
构造
template<typename T>
DynArray<T>::DynArray()
:m_pSource(nullptr), m_nSize(0), m_nCapacity(0)
{
m_pSource = m_alloc.allocate(100);
if (m_pSource == nullptr)
{
throw "out of memory";
}
else
{
m_nSize = 0;
m_nCapacity = 100;
}
}
拷贝构造
template<typename T>
DynArray<T>::DynArray(const DynArray<T>& arrElements_)
: m_pSource(nullptr), m_nSize(0), m_nCapacity(0)
{
m_pSource = m_alloc.allocate(arrElements_.m_nCapacity);
if (m_pSource == nullptr)
{
throw "out of memory";
}
else
{
m_nSize = arrElements_.m_nSize;
m_nCapacity = arrElements_.m_nCapacity;
std::uninitialized_copy_n(arrElements_.m_pSource, arrElements_.m_nSize, m_pSource);
}
}
赋值
template<typename T>
DynArray<T>& DynArray<T>::operator=(const DynArray<T>& arrElements_)
{
if (&arrElements_ == this)
{
return *this;
}
this->~DynArray();
m_pSource = m_alloc.allocate(arrElements_.m_nCapacity);
if (m_pSource == nullptr)
{
throw "out of memory";
}
else
{
m_nSize = arrElements_.m_nSize;
m_nCapacity = arrElements_.m_nCapacity;
std::uninitialized_copy_n(arrElements_.m_pSource, arrElements_.m_nSize, m_pSource);
}
}
析构
template<typename T>
DynArray<T>::~DynArray()
{
if (m_pSource == nullptr)
{
return;
}
T* _pEnd = m_pSource + m_nSize;
while (_pEnd != m_pSource)
{
m_alloc.destroy(--_pEnd);
}
// 内存释放
m_alloc.deallocate(m_pSource, m_nCapacity);
m_pSource = nullptr;
m_nSize = 0;
m_nCapacity = 0;
m_pSource = m_alloc.allocate(100);
if (m_pSource == nullptr)
{
throw "out of memory";
}
else
{
m_nSize = 0;
m_nCapacity = 100;
}
}
插入
template<typename T>
void DynArray<T>::Insert(int nIndex_, const T& value_)
{
if (nIndex_ > m_nSize)
{
throw "Insert position error";
}
Check(m_nSize + 1);
m_alloc.construct(m_pSource + m_nSize, value_);
m_nSize++;
for (int _i = m_nSize - 1; _i >= nIndex_; _i--)
{
*(m_pSource + _i + 1) = *(m_pSource + _i);
}
*(m_pSource + nIndex_) = value_;
}
删除
template<typename T>
void DynArray<T>::DeleteByIndex(int nIndex_)
{
if (nIndex_ < 0
|| nIndex_ >= m_nSize)
{
return;
}
// 前移
for (int _i = nIndex_ + 1; _i < m_nSize; _i++)
{
*(m_pSource + _i - 1) = *(m_pSource + _i);
}
m_alloc.destroy(m_pSource + m_nSize);
m_nSize--;
if (m_nSize <= m_nCapacity / 4)
{
Shrink();
}
}
查找
template<typename T>
int DynArray<T>::Find(std::function<bool(const T&)> fun_) const
{
int _nPosIndex = -1;
for (int _i = 0; _i < m_nSize; _i++)
{
if (fun_(*(m_pSource + _i)))
{
_nPosIndex = _i;
break;
}
}
return _nPosIndex;
}
索引
template<typename T>
T& DynArray<T>::operator[](int nIndex_)
{
if (nIndex_ < 0
|| nIndex_ >= m_nSize)
{
throw "index is error";
}
return *(m_pSource + nIndex_);
}
排序
template<typename T>
void DynArray<T>::Sort(std::function<int(const T&, const T&)> fun_)
{
if (m_nSize <= 1)
{
return;
}
Algorithm::Sort::Helper::QuickSort<T>(m_pSource,
m_pSource + m_nSize,
fun_);
return;
}
动态增大
template<typename T>
void DynArray<T>::Check(int nSize_)
{
if (m_nCapacity >= nSize_)
{
return;
}
int _nSize = m_nSize;
int _nCapacity = nSize_ * 2;
T* _pSource = m_alloc.allocate(_nCapacity);
if (_pSource == nullptr)
{
throw "out of memory";
}
else
{
std::uninitialized_copy_n(m_pSource, m_nSize, _pSource);
this->~DynArray();
m_pSource = _pSource;
m_nSize = _nSize;
m_nCapacity = _nCapacity;
}
}
动态减小
template<typename T>
void DynArray<T>::Shrink()
{
int _nSize = m_nSize;
int _nCapacity = (m_nCapacity / 2) > 100 ? (m_nCapacity / 2) : 100;
T* _pSource = m_alloc.allocate(_nCapacity);
if (_pSource == nullptr)
{
throw "out of memory";
}
else
{
std::uninitialized_copy_n(m_pSource, m_nSize, _pSource);
this->~DynArray();
m_pSource = _pSource;
m_nSize = _nSize;
m_nCapacity = _nCapacity;
}
}
时间复杂度
以下分析皆假设数组内元素个数为n
构造
时间复杂度Θ(1)
拷贝构造
时间复杂度Θ(n)
赋值
时间复杂度Θ(n)
析构
时间复杂度Θ(n)
插入
最坏下Θ(n)
删除
最坏下Θ(n)
搜索
最坏下Θ(n)
位置索引
时间复杂度Θ(1)
排序
时间复杂度Θ(nlg(n))
动态增大
时间复杂度Θ(n)
动态收缩
时间复杂度Θ(n)