C++STL -- vector实现
STL的vector简化实现
本质
vector说到底就是一个动态数组,我们需要做的就是管理动态数组的内存,和元素的增加,删除,移动等。
template <typename T>
class vector {
public:
typedef T* iterator;
typedef T& reference;
protected:
iterator start; //第一个元素
iterator finish; //最后一个元素的后面一位
iterator end_of_storage; //capacity的位置
public:
...
};
构造函数
实现很简单,就是创建一个动态数组,然后将iterator赋值好就行。
public:
vector() : start(0), finish(0), end_of_storage(0) {};
vector(unsigned n, const T& value) { init(n, value); }
explicit vector(unsigned n) { init(n, T()); }
这里我使用了辅助初始化的函数init(其他函数也要用),其实现如下:
private:
void init(unsigned n, const T& value) {
assert(n > 0);
start = new T[n];
finish = start + n;
end_of_storage = finish;
for(int i = 0; i < n; i++) {
start[i] = value;
}
}
析构函数
主要就是进行内存释放,指针赋空值。
~vector() { destory(); }
这里用到了辅助函数(其他函数也要用),实现如下:
private:
void destory() {
delete[] start;
start = finish = end_of_storage = nullptr;
}
assign
先判断当前容量是否足够,不足则先分配两倍的容量,然后再赋值。
void assign(unsigned num, const T& value) {
while(num > capacity()) {
extendDouble();
}
for(int i = 0; i < num; i++) {
start[i] = value;
}
}
void assign(iterator first, iterator last) {
unsigned num = (unsigned)(last - first);
while(num > capacity()) {
extendDouble();
}
for(int i = 0; i < num; i++) {
start[i] = first[i];
}
}
这里用到辅助函数extendDouble来分配两倍的容量,实现如下:
void extendDouble() {
//确定两倍容量的值
unsigned newCapacity = capacity() * 2;
if(newCapacity == 0) newCapacity = 1;
//将旧值放到新数组中
T* newMen = new T[newCapacity];
unsigned oldSize = size();
for(int i = 0; i < oldSize; i++) {
newMen[i] = start[i];
}
//施放旧数组,赋值为新数组
destory();
start = newMen;
finish = start + oldSize;
end_of_storage = start + newCapacity;
}
back
reference back() { return start[size()-1]; }
begin
iterator begin() { return start; }
capacity
unsigned capacity() const {
return (unsigned)(end_of_storage - start);
}
clear
void clear() { finish = start; }
empty
bool empty() const { return size() == 0; }
end
iterator end() { return finish; }
erase
对于删除操作,主要就是要将被删除元素后面的元素向前移动。
iterator erase(iterator pos) {
assert(pos < finish);
//将之后的元素向前移动
unsigned delta = (unsigned)(pos - start);
for(int i = delta; i < size()-1; i++)
start[i] = start[i+1];
finish--;
return pos;
}
iterator erase(iterator first, iterator last) {
assert(last > first && last < finish);
unsigned firstIndex = (unsigned)(first - start);
unsigned lastIndex = (unsigned)(last - start);
for(int i = firstIndex, m = lastIndex; m < size(); i++, m++)
start[i] = start[m];
finish -= (unsigned)(last - first);
return first;
}
从这里可以看出,被删除元素后面的iterator都失效,而前面的iterator则依然有效。
front
reference front() { return start[0]; }
insert
insert实现复杂一点,需要先分配好足够的容量,然后将插入点后的元素全部移动n个单位,最后将n个值依次从插入点开始赋值。
void insert(iterator pos, unsigned n, const T& value) {
unsigned posIndex = (unsigned)(pos - start);
unsigned newSize = size() + n;
//分配好需要的容量
while(newSize > capacity())
extendDouble();
pos = start + posIndex;
unsigned numNeedMove = (unsigned)(finish - pos);
//将插入点后面的元素先放到一个临时数组存起来
T* temp = new T[numNeedMove];
for(int i = 0; i < numNeedMove; i++) {
temp[i] = pos[i];
}
//将n个值依次从插入点开始赋值
for(int i = 0; i < n; i++) {
pos[i] = value;
}
//将插入点后的元素重新放回到数组中
for(int i = n; i < n+numNeedMove; i++) {
pos[i] = temp[i-n];
}
finish = start + newSize;
delete temp;
temp = nullptr;
}
void insert(iterator pos, const T& value) {
insert(pos, 1, value);
}
void insert(iterator pos, iterator first, iterator last) {
unsigned n = (unsigned)(last - first);
unsigned posIndex = (unsigned)(pos - start);
unsigned newSize = size() + n;
while(newSize > capacity())
extendDouble();
pos = start + posIndex;
unsigned numNeedMove = (unsigned)(finish - pos);
T* temp = new T[numNeedMove];
for(int i = 0; i < numNeedMove; i++) {
temp[i] = pos[i];
}
for(int i = 0; i < n; i++) {
pos[i] = first[i];
}
for(int i = n; i < n+numNeedMove; i++) {
pos[i] = temp[i-n];
}
finish = start + newSize;
delete temp;
temp = nullptr;
}
pop_back
void pop_back() {
if(empty()) return;
finish--;
}
push_back
void push_back(const T& value) {
//容量足够
if(finish != end_of_storage) {
start[size()] = value;
finish++;
}
//容量不足
else {
unsigned oldSize = size();
extendDouble();
start[oldSize] = value;
}
}
reserve
void reserve(unsigned n) {
if(n <= capacity()) return;
unsigned oldSize = size();
T* newOne = new T[n];
for(int i = 0; i < size(); i++) {
newOne[i] = start[i];
}
destory();
start = newOne;
finish = start + oldSize;
end_of_storage = start + n;
}
resize
void resize(unsigned s, const T& value) {
if(s < size())
erase(begin() + s, end());
else
insert(end(), s - size(), value);
}
void resize(unsigned s) { resize(s, T()); }
C++STL -- vector实现的更多相关文章
- C++ STL vector容器学习
STL(Standard Template Library)标准模板库是C++最重要的组成部分,它提供了一组表示容器.迭代器.函数对象和算法的模板.其中容器是存储类型相同的数据的结构(如vector, ...
- STL vector
STL vector vector是线性容器,它的元素严格的按照线性序列排序,和动态数组很相似,和数组一样,它的元素存储在一块连续的存储空间中,这也意味着我们不仅可以使用迭代器(iterator)访问 ...
- STL vector用法介绍
STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和f ...
- STL vector+sort排序和multiset/multimap排序比较
由 www.169it.com 搜集整理 在C++的STL库中,要实现排序可以通过将所有元素保存到vector中,然后通过sort算法来排序,也可以通过multimap实现在插入元素的时候进行排序.在 ...
- STL vector 用法介绍
介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...
- STL vector使用方法介绍
介绍 这篇文章的目的是为了介绍std::vector,怎样恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...
- stl——vector详解
stl——vector详解 stl——vector是应用最广泛的一种容器,类似于array,都将数据存储于连续空间中,支持随机访问.相对于array,vector对空间应用十分方便.高效,迭代器使ve ...
- C++STL vector详解(杂谈)
介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...
- C++ stl vector介绍
转自: STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if ...
- 浅谈C++ STL vector 容器
浅谈C++ STL vector 容器 本篇随笔简单介绍一下\(C++STL\)中\(vector\)容器的使用方法和常见的使用技巧.\(vector\)容器是\(C++STL\)的一种比较基本的容器 ...
随机推荐
- Linux C 字符函数 getchar()、putchar() 与 EOF 详解
首先给出<The_C_Programming_Language>这本书中的例子: #include <stdio.h> int main() { int c; c = getc ...
- HMac基本介绍
基本介绍 HMAC(散列消息身份验证码: Hashed Message Authentication Code) 它不是散列函数,而是采用散列函数(MD5 or 或SHA)与共享密钥一起使用的消息身份 ...
- android:layout_height、android:layout_width、android:height、android:width的关系与区别
一直一来对android:layout_height.android:layout_width.android:height.android:width这几个属性的关系有些不理解,既然有了androi ...
- Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)
题目链接:http://codeforces.com/contest/522/problem/D 题目大意: 给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...
- POJ 3678 Katu Puzzle
Description 给出一个关系,包括 And,Xor,Or 问是否存在解. Sol 经典的2-SAT问题. 把每个值看成两个点,一个点代表选 \(0\) ,另一个代表选 \(1\) . 首先来看 ...
- NSCache
今天在优化的时候,用了NSCache,感觉没什么两样(视觉上).按理内存缓存,怎么也比从硬盘读取的要快.. dispatch_async(dispatch_get_global_queue(, ), ...
- 【krpano】汉化Web VR设置界面
欢迎加入qq群551278936讨论krpano解密技术以及获取最新软件 krpano 1.19支持了Web VR功能,允许以VR的方式查看全景图,配合上VR设备可以实现VR效果. 在VR方式查看时, ...
- NHibernate3快速上手教程FluentNHibernate配置与DBHelper
很多学习NHibernate的新手很容易卡在配置文件这一关,正所谓万事开头难,上手后再配合官方文档就比较容易了. 网上关于配置文件的资料非常多,但由于版本的问题,许多老的教程中都没有明确指出类库的版本 ...
- jQuery hover事件
hover(over,out)一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法.这是一个自定义的方法,它为频繁使用的任务提供了一种"保持在其中"的状态. 当鼠标移动到 ...
- TFS二次开发系列:三、TFS二次开发的第一个实例
首先我们需要认识TFS二次开发的两大获取服务对象的类. 他们分别为TfsConfigurationServer和TfsTeamProjectCollection,他们的不同点在于可以获取不同的TFS ...