1.容器的概念
容器是保存一组给定类型对象的类型。每个标准类型都是一个模版类型。为了定义一个容器,我们必须指定保存在容器中的元素的类型。除了array之外,标准库容器都是大小可变的
2.容器的分类
容器分为两类: (1)关联容器 (2)顺序容器
顺序容器:保存相同类型对象有序集合的类型。顺序容器中的元素通过位置来访问
关联容器:元素的位置由相关联的关键字值决定的。也就是所关联容器中元素的位置与关键字关联。
顺序容器分为三种:
- vector 支持快速随机访问
- list 支持快速插入/删除
- deque 双端队列
下面介绍顺序容器:(顺序容器都提供了快速顺序访问元素的能力)
(1)vector:可变大小数组,支持快速的随机访问,只能在末尾实现高效的插入/删除。
(2)list:双向链表,支持任意位置快速插入,插入和删除速度都很快,很方便。
(3)deque:双端队列,支持快速随机访问,在首尾插入、删除速度很快。
(4)forward_lis:单向链表,只能顺序访问,支持任意位置的快速插入/删除。
(5)array:固定大小数组,支持随机快速访问,不能删除或填加元素
顺序容器的使用方法:
(1)除了array固定大小,其他顺序容器都提供高效、灵活的内存管理,可以添加、删除、扩张和收缩容器。
(2)string 和 vector 等容器将元素保存在连续的内存空间中,即其元素的内存是连续存储的,可以支持下标操作。
(3)通常使用 vector 是很好的选择,除非有更好的理由选择其他容器。
(4)如果在读取时需要插入元素,但是随后需要使用随机访问元素,根据情况可以选择sort重排vector,更通用情况是输入阶段使用list,输入完成后,将list中的内容放入到一个vector中。
顺序容器配置器:
关于new,delete与配置器:
对于new,我们都是先配置内存,然后调用对应的构造函数;而delete则是先调用对应的析构函数,然后释放内存。
只需要开辟一定大小内存,并不想去构造对象,删除是只进行对象析构,但不释放这块内存,以后继续留用。
使用容器的空间配置器的目的:把对象的内存开辟和对象的构造分开;把对象的析构和内存释放分开。
实现容器的配置器:
template<typename T>
class Allocator
{
public:
T* allocate(size_t size) // 开辟内存
{
return (T*)malloc(size);
}
void deallocate(void *ptr) // 释放内存
{
free(ptr);
}
void construct(T *ptr, const T &val) // 构造
{
new (ptr) T(val);
}
void destroy(T *ptr) // 析构
{
ptr->~T();
}
};
实现带空间配置器Vector
// 实现容器的空间配置器
template<typename T>
class Allocator
{
public:
T* allocate(size_t size) // 开辟内存
{
return (T*)malloc(size);
}
void deallocate(void *ptr) // 释放内存
{
free(ptr);
}
void construct(T *ptr, const T &val) // 构造
{
new (ptr) T(val);
}
void destroy(T *ptr) // 析构
{
ptr->~T();
}
};
template<typename T,
typename allocator = Allocator<T>>
class Vector
{
public:
// 按指定size进行构造,size个空间,没有元素
Vector(int size = 0)
:mCur(0), mSize(size)
{
if (size == 0)
{
mpVec = nullptr;
}
else
{
//mpVec = new T[mSize];
mpVec = mAllocator.allocate(mSize * sizeof(T));
}
}
// 按指定size进行构造,添加size个元素,元素值是val
Vector(int size, const T &val)
:mCur(size), mSize(size)
{
mpVec = new T[mSize];
for (int i = 0; i < mSize; ++i)
{
mpVec[i] = val;
}
}
// 按[first, last)区间的元素来构造Vector
Vector(T *first, T *last)
{
int size = last - first;
mSize = size;
mpVec = new T[mSize];
for (mCur=0; first < last; ++first)
{
mpVec[mCur++] = *first;
}
}
~Vector()
{
//delete[]mpVec;
// 析构有效的对象
for (int i = 0; i < mCur; ++i)
{
mAllocator.destroy(mpVec+i);
}
// 释放内存
mAllocator.deallocate(mpVec);
}
// 从末尾添加元素
void push_back(const T &val)
{
if (full())
resize();
//mpVec[mCur++] = val;
mAllocator.construct(mpVec+mCur, val);
mCur++;
}
// 从末尾删除元素
void pop_back()
{
if (empty())
return;
--mCur;
mAllocator.destroy(mpVec+mCur);
}
bool full()const { return mCur == mSize; }
bool empty()const { return mCur == 0; }
// 返回容器元素的个数
int size()const { return mCur; }
// Vector的迭代器
class iterator
{
public:
iterator(T *p = nullptr) :_ptr(p) {}
bool operator!=(const iterator &it)
{
return _ptr != it._ptr;
}
void operator++() { _ptr++; }
T& operator*() { return *_ptr; }
private:
T *_ptr;
};
iterator begin() { return iterator(mpVec); }
iterator end() { return iterator(mpVec + size()); }
private:
T *mpVec;
int mCur;
int mSize;
allocator mAllocator; // 存储容器的空间配置器
// 容器内存2倍扩容
void resize()
{
if (0 == mSize)
{
mCur = 0;
mSize = 1;
mpVec = mAllocator.allocate(mSize * sizeof(T));
}
else
{
T *ptmp = mAllocator.allocate(2 * mSize * sizeof(T));
for (int i = 0; i < mSize; ++i)
{
mAllocator.construct(ptmp + i, mpVec[i]);
}
for (int i = 0; i < mSize; ++i)
{
mAllocator.destroy(mpVec + i);
}
mAllocator.destroy(mpVec);
mpVec = ptmp;
mSize *= 2;
}
}
};
class A
{
public:
A() :p(new int[2]) { cout << "A()" << endl; }
A(const A &src) { cout << "A(const A&)" << endl; }
~A() { cout << "~A()" << endl; }
private:
int *p;
};
int main()
{
A a1, a2, a3;
// 这里只需要空间,不需要构造对象 malloc
Vector<A> vec(100);
vec.push_back(a1);
vec.push_back(a2);
vec.pop_back();
vec.push_back(a3);
}
实现不带空间配置器vector
template<typename T>
class Vector
{
public:
// 按指定size进行构造,size个空间,没有元素
Vector(int size = 0):mCur(0),mSize(size)
{
if (size == 0)
{
mpVec = nullptr;
}
else
{
mpVec = new T[mSize];
}
}
// 按指定size进行构造,添加size个元素,元素值是val
Vector(int size, const T &val = T()):mCur(size)
{
mpVec = new T[size];
mSize = size;
for (int i = 0; i < size; ++i)
{
mpVec[i] = val;
}
}
// 按[first, last)区间的元素来构造Vector
Vector(T *first, T *last)
{
int size = last - first;
mSize = size;
mpVec = new T[mSize];
for (mCur = 0; mCur < size; first++)
{
mpVec[mCur++] = *first;
}
}
// 从末尾添加元素
void push_back(const T &val)
{
if (full())
{
resize();
}
mpVec[mCur++] = val;
}
// 从末尾删除元素
void pop_back()
{
if (empty())
{
return;
}
--mCur;
}
bool full()const
{
return mCur == mSize;
}
bool empty()const
{
return mSize == 0;
}
// 返回容器元素的个数
int size()const
{
return mCur;
}
// Vector的迭代器
class iterator
{
public:
iterator(T *argv = nullptr):_mpVec(argv) {}
void operator++()
{
_mpVec++;
}
bool operator!=(const iterator &rhs)
{
return _mpVec != rhs._mpVec;
}
T& operator*()
{
return *_mpVec;
}
private:
T *_mpVec;
};
iterator begin()
{
return iterator(mpVec);
}
iterator end()
{
return iterator(mpVec + size());
}
private:
T *mpVec;
int mCur;
int mSize;
// 容器内存2倍扩容
void resize()
{
if (empty())
{
mpVec = new T[1];
mSize = 1;
mCur = 0;
}
else
{
T *tmp = new T[mSize * 2];
for (int i = 0; i < mSize; i++)
{
tmp[i] = mpVec[i];
}
delete []mpVec;
mpVec = tmp;
mSize *= 2;
}
}
};
int main()
{
Vector<int> vec1; // 底层不开辟空间
for (int i = 0; i < 20; ++i)
{
vec1.push_back(rand() % 100 + 1);
}
cout << vec1.size() << endl;
// 用通用的迭代器遍历方式,遍历vec1,并打印容器中所有的元素值
Vector<int>::iterator it = vec1.begin();
for (; it != vec1.end() ; ++it)
{
cout << *it << " ";
}
cout << endl;
Vector<int> vec2(10, 20);
Vector<int>::iterator it1 = vec2.begin();
for (; it1 != vec2.end() ; ++it1)
{
cout << *it1 << " ";
}
cout << endl;
int arr[] = { 12,4,56,7,89 };
Vector<int> vec3(arr, arr + sizeof(arr) / sizeof(arr[0]));
Vector<int>::iterator it2 = vec3.begin();
for (; it2 != vec3.end() ; ++it2)
{
cout << *it2 << " ";
}
cout << endl;
return 0;
}