走进STL - 序列式容器(常用篇)
时间:2022-07-23
本文章向大家介绍走进STL - 序列式容器(常用篇),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在序列式容器的大家庭里,比较常用的还是vector和list。 本篇就重点讲这两个容器的实现。
1、vector
文字表诉的部分文章开头的那篇博客基本讲完了,我们直接来看vector的定义摘要。 哈哈,先把工具包都备齐。然后看代码:
1.1 vector类设计
/*alloc是SGI STL的空间配置器*/
template <class T,class Alloc = alloc> //模板偏特化,这个工具包我没准备
class vector
{
//以下这一块属于迭代器使用
public :
typedef T value_type;
typedef value_type* pointer;
typedef value_type* iterator;
typedef value_type& reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
//以下simple_alloc属于SGI STL 空间配置器
typedef simple_alloc<value_type,Alloc> data_allocator;
iterator start; //表示目前使用的空间的头
iterator finish;//表示目前使用的空间的尾
iterator end_of_storage; //表示目前可用的空间的尾
void insert_aux(iterator position,const T& x);
void deacllocate()
{
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 - end();}
bool empty() const {return end_of_storage == end();}
reference operate[](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();}
void push_back(const T& x)
{
if(finish !=end_of_storage)
{
construct(finish,x);
++finish;
}
else
insert_aux(end(),x);
}
void pop_back()
{
--finish;
destroy(finish);
}
//从这里可以看出是直接覆盖原位置数据,然后回收最后一个节点
iterator erase(iterator position)
{
if(position +1 != end())
copy(position + 1,finish,position); //这个函数属于算法 将后续元素前移
--finish;
destroy(finish);
return position;
}
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());}
void clear(){erase(begin(),end());}
protect:
//配置空间并填满
iterator allocate_and_fill(size_type n,const T& x)
{
iterator result = data_allocator::allocate(n);
uninitialized_fill_n(result,n,x); //内存配置函数,不过那篇太长了,我就吧un-这一块给咔嚓了
return result;
}
}
1.2 vector其他
源码之前,了无秘密。我还能补充啥?还能补充的在文章开头那篇关于vector的文章里面也都说完了。。。
2、list
关于list的节点设计、迭代器设计、数据结构,题头那篇已经详尽。 list增删的坑,可以看:走近STL - 填上List删除的大坑
好,我们也是直接看源码吧,其实和上面的vector有很多相通之处的。
2.1 节点设计
//为了完整性,我们还是先看一下节点设计
template <class T>
struct __list_node
{
typedef void * void_pointer;
void_pointer prev;
void_pointer next;
T data;
} //显然,这是一个双向链表,图就不再画一遍了
2.2 迭代器设计
//list的迭代器不像vector,普通指针是不行的
//以下是list迭代器的设计
template <class T,class Ref,class Ptr>
struct __list_iterator
{
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef __list_node<T>* link_type;
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T,Ref,Ptr> self;
typedef bidirectional_iterator_tag iterator_category;
link_type node; //用于指向内部节点
//构造函数
__list_iterator(link_type x):node(x){}
__list_iterator(){}
__list_iterator(const iterator& x):node(x.node){}
//运算符重载
bool operator==(const self& x) const {return node == x.node}
bool operator!=(const self& x) const {return node != x.node}
reference operator*() const {return (*node).data;}
pointer operator->() const {return &(operator*());}
self& operator++() //对节点进退操作,vector中并没有重载这些
{
node = (link_type)((*node).next);
return *this;
}
self& operator++(int)
{
self tmp = *this;
++*this;
return tmp;
}
self& operator--()
{
node = (link_type)((*node).prev);
return *this;
}
self& operator++(int)
{
self tmp = *this;
++*this;
return tmp;
}
}
2.3 数据结构
SGI list 不止是一个双向链表,它还是环状的。所以它只要一个指针便可以遍历整个链表。
如果让指针node指向刻意置于尾端的一个空白节点,node便能符合STL“前闭后开”的原则。
至于和vector重复的方法像begin()这些的就不再提一遍了。
我们来看看list特有的方法:
//首先争议比较大的删除函数先看
//都没必要争议,源码之前,了无秘密
iterator erase(iterator position)
{
link_type next_node = link_type(position.node->next);
link_type prev_node = link_type(position.node->prev);
//先吧前后都接管了
//接下来把前后无缝对接
prev_node->next = next_node;
next_node->prev = prev_node;
//然后把那个节点回收
destory_node(position.node);
return iterator(next_node); // 看清楚返回值
}
算了,算法部分放到后面算法区写吧 这篇就到这里啦
- 浅谈JavaScript的事件(事件委托)
- 浅谈JavaScript的Canvas(绘制图形)
- 浅谈JavaScript的事件(事件流)
- 浅谈JavaScript的函数表达式(递归)
- 浅谈JavaScript的事件(事件模拟)
- Spring中@Transactional事务回滚实例及源码
- 浅谈JavaScript的函数表达式(闭包)
- 浅谈JavaScript的事件(事件类型)
- 17年编程生涯的三大经验总结
- 浅谈JavaScript的面向对象程序设计(四)
- 浅谈JavaScript的事件(事件对象)
- 浅谈JavaScript的字符串的replace方法
- 西方红玫瑰和辣条先生黑产组织深度分析报告
- HTTPS劫匪木马暴力升级:破坏ARK攻击杀软
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Nginx 反向代理
- 非关系型数据库 Redis
- MyBatis 简单使用
- 数值分析常见习题解答
- Spring Web MVC 文件上传
- Leetcode 45 跳跃游戏 II (贪心+数学)
- Leetcode 第23场双周赛D 5363. 做菜顺序(DP,贪心)
- Leetcode 22. 括号生成 (括号匹配,dfs)
- MQ 系列之 ActiveMQ 介绍
- Python Tips(1) 数字与字符串之间转换,采用内置函数
- Spring Web MVC 拦截器
- Spring Web MVC 响应消息
- Codeforces Round #633 (Div. 2)D Edge Weight Assignment(构造、树的权值异或)
- Spring Web MVC 请求消息
- Codeforces Round #633 (Div. 2) A Filling Diamonds (假题,观察)