STL學習筆記--4、序列式容器之vector
阿新 • • 發佈:2019-02-07
常見的資料結構:array陣列,list連結串列,tree樹,stack棧,queue佇列,hash table散列表,set集合,map對映……
根據資料在容器中的排列分為:序列式sequence和關聯式associative。
序列式容器之vector
1、vector VS array:
- array是靜態空間,一旦配置則無法改變;
- vector是動態空間,隨著元素的加入,內部機制會自動擴充新的空間來容納新的元素。
實現技術:對大小的控制和重新配置時的資料移動效率。
擴充空間:配置新空間、資料移動、釋放舊空間。
2、定義摘要:
在SGI中,#include<stl_vector.h>
在STl標準中只需要
#include<vector>
template <class T, class Alloc = alloc>
class vector {
public:
//巢狀型別定義
typedef T value_type;
typedef value_type* pointer;
//迭代器型別為隨機存取型別
//RandomAccessIterator
typedef value_type* iterator;
typedef value_type& reference;
typedef size_t size_type;
protect:
//方便以元素為單位配置大小
typedef simple_alloc<value_type, Alloc> data_allocator;
//表示目前使用的空間頭
iterator start;
//表示目前使用的空間尾
iterator finish;
//表示目前可用的空間尾
iterator end_of_storage;
//插入元素。有備用空間直接插入,無備用空間則進行空間分配
void insert_aux(iterator position, const T& x);
//呼叫全域性deallocate來完成
void deallocate() {
if (start)
data_allocator::deallocate(start,end_of_storage - start);
}
void fill_initialize(size_type n, const T& value)
{
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}
public:
iterator begin() { return start; }
iterator end() { return finish; }
//容器使用的長度
size_type size() const {
return size_type(end() - begin());
}
//容器可用的長度
size_type capacity() const {
return size_type(end_of_storage - begin());
}
bool empty() const { return begin() == end(); }
reference operator[](size_type n) { return *(begin() + n); }
//建構函式
//預設建構函式
vector() : start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T& value) { fill_initialize(n, value); }
vector(int n, const T& value) { fill_initialize(n, value); }
vector(long n, const T& value) { fill_initialize(n, value); }
//顯示版本的建構函式
explicit vector(size_type n) { fill_initialize(n, T()); }
//解構函式
~vector() {
destroy(start, finish);
deallocate();
}
//第一個元素引用
reference front() { return *begin(); }
//最後一個元素引用
reference back() { return *(end() - 1); }
//push_back,呼叫了insert_aux
void push_back(const T& x) {
if (finish != end_of_storage) {//還有備用空間
construct(finish, x);
++finish;
}
else//以無備用空間
insert_aux(end(), x);
}
//pop_back()
void pop_back() {
--finish;
destroy(finish);
}
//erase版本一:接受一個迭代器
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position);
--finish;
destroy(finish);
return position;
}
//erase版本二:接受二個迭代器。清除迭代器範圍的元素
iterator erase(iterator first, iterator last) {
iterator i = copy(last, finish, first);
destroy(i, finish);
finish = finish - (last - first);
return first;
}
//resize():為容器重新定義長度。
//若new_size小於size則,丟棄多餘部分
//若new_size大於size則,空出的部分進行T型別的值初始化
void resize(size_type new_size, const T& x) {
if (new_size < size())
erase(begin() + new_size, end());
else
insert(end(), new_size - size(), x);
}
void resize(size_type new_size){resize(new_size, T());}
//clear()清空容器
void clear() { erase(begin(), end()); }
protected:
//配置容器並填滿內容,填n個x
iterator allocate_and_fill(size_type n, const T& x) {
iterator result = data_allocator::allocate(n);
__STL_TRY {
uninitialized_fill_n(result, n, x);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
3、vector迭代器
vector維護的是連續線性空間。支援隨機存取,迭代器型別為RandomAccessIterator。
4、vector資料結構
//表示目前使用的空間頭
iterator start;
//表示目前使用的空間尾
iterator finish;
//表示目前可用的空間尾
iterator end_of_storage;
vector實際配置的大小總是大於等於客戶端需求的大小,以備將來的擴充。
增加新元素時,如果超出當時容量,則容量進行兩倍擴充;若兩倍容量不足時,則擴充足夠大的容量。
容量的擴充需要進行:重新配置、元素移動、釋放舊空間。
5、構造和記憶體管理:
vector預設使用alloc作為空間配置器;
uninitialized_fill_n()
根據第一個引數的型別特性type traits決定演算法使用(__true_type
)fill_n()或是反覆呼叫(__false_type
)construct()來完成。
//push_back,呼叫了insert_aux
void push_back(const T& x) {
if (finish != end_of_storage) {//還有備用空間
construct(finish, x);
++finish;
}
else//以無備用空間
insert_aux(end(), x);
}
演算法實現:insert_aux(end(), x);
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
if (finish != end_of_storage) {//還有備用空間
//在備用空間起始處構造元素,以finish - 1位置處的值作為初值
construct(finish, *(finish - 1));
++finish;
T x_copy = x;
//將[position,finish-2)處的值拷貝到[(finish - 1)-((finish - 2)-(position)),finish - 1)
copy_backward(position, finish - 2, finish - 1);
*position = x_copy;
}
else {//無備用空間
const size_type old_size = size();
//確定新構造的空間的長度
//若舊空間為0,則構造1個
//若舊空間非零,則構造舊空間的兩倍
const size_type len = old_size != 0 ? 2 * old_size : 1;
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
//舊空間的元素拷貝到新空間
new_finish = uninitialized_copy(start, position, new_start);
//新元素指定為x
construct(new_finish, x);
//調整使用空間大小
++new_finish;
//新元素裝入
new_finish = uninitialized_copy(position, finish, new_finish);
}
#ifdef __STL_USE_EXCEPTIONS
//若新空間分配失敗,則釋放所有新分配的空間
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
#endif /* __STL_USE_EXCEPTIONS */
//釋放舊空間
destroy(begin(), end());
deallocate();
//調整迭代器,指向新空間
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
6、元素操作:erase()
兩個引數版本,釋放區域性區間的清除操作示意圖:
7、元素操作:insert()
insert(iterator position, size_type n, const T& x)
1、若備用空間大於等於新增元素個數
(end_of_storage-finish) >= n
計算插入點之後現有的元素個數
elems_after=finish-position;
情況一:1)、若**插入點之後的現有元素個數**大於**新增元素個數**
elems_after>n
{
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy);
}
情況二:2)、若**插入點之後的現有元素個數**小於等於**新增元素個數**
elems_after<=n
{
uninitialized_fill_n(finish, n - elems_after, x_copy);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
fill(position, old_finish, x_copy);
}
2、若備用空間小於新增元素個數
(end_of_storage-finish) < n
1)決定新的長度。舊長度的兩倍或舊長度+新增元素個數。
len=old_size+max(old_size,n)
2)配置記憶體空間
iterator new_start =data_allocator::allocate(len);
iterator new_finish = new_start;
情況三:3)資料元素的移動
{
//舊空間的插入點之前的元素copy到新空間
new_finish = uninitialized_copy(start, position, new_start);
//新增的元素初值為x,填入到新空間
new_finish = uninitialized_fill_n(new_finish, n, x);
//舊空間的插入點之後的元素copy到新空間
new_finish = uninitialized_copy(position, finish, new_finish);
}
3、如果分配新空間出現異常,則銷燬新分配的記憶體,丟擲異常
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
#endif /* __STL_USE_EXCEPTIONS */
4、清除並釋放舊空間記憶體
destroy(start, finish);
deallocate();
5、調整迭代器,指向新空間
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
情況一:備用空間充足,且elems_after>n
n=2; elems_after=2; 備用空間end_of_storage-finish=2;
情況二:備用空間充足,且elems_after<=n
n=4; elems_after=2; 備用空間end_of_storage-finish=3;
情況三:備用空間不足容納新增元素
n=3; 備用空間end_of_storage-finish=2;