一、什么是STL?
STL(标准模板库)是c++标准库的最重要组成部分,它既是一个可复用的组件库,又是一个包罗算法和数据结构的软件框架。
二、STL版本
要求必须开源。功能一扬,不限制实现方式。
- HP版本
- PJ版本(windows-vs)
- RW版本
- SGI版本(linux) 观看时看此版本 剖析时选V3.0
三、STL六大组件
- 容器(各种数据结构——wector、list、map、set等)
- 迭代器(扮演容器和算法的胶合剂)
- 空间配置器(负责内存空间的分配与管理)
- 配接器(一种修饰容器、仿函数或者迭代器接口的东西)
- 算法(各种常用算法——sort、search、copy等)
- 仿函数(行为类似函数的类,用作算法的某种策略)
推荐书籍: 侯捷 STL源码剖析
剖析工具: Source Insight 、 vs201x (2013)、 everything
推荐网址:
www.cplusplus.com
四、容器
vector 可动态增长的数组,实现了顺序容器。
list 带头双向循环链表
(一)迭代器原理
迭代器就像指针一样。
迭代器有两种形态:反向(reverse)迭代器【与rend和rbegin对应】
正向迭代器【对应end和begin】
const的正向迭代器
const的反向迭代器
(二)学会使用list和vector
vector_list.h
#pragma once #include <list> #include <vector> void test_list() { list<int> l1; l1.push_back(1); l1.push_back(2); l1.push_back(3); l1.push_back(4); l1.push_back(5); //遍历打印时: //使用l1.print(); 有很大的问题 eg:假设只想遍历前10个或只遍历偶数 必须把数据给我,让我决定怎么选择、怎么走顺序 //两种方式:一 把你的结构暴露给我(暴露链表头) //暴露出内部链表的结构——带头双向链表,产生的问题1:破坏封装性 问题2:增加了使用成本 //二 迭代器 //作用:方便访问容器的数据 list<int>::iterator it = l1.begin();//定义个对象it 左闭右开[begin,end) size_t n = 10; while (it != l1.end() && n--) //只打印前10个数,若有10个数的话 后置-- { if (*it % 2) { cout << *it << " "; } //其实迭代器就像节点指针一样,但解引用后是结点中的数据(节点指针解引用后得到的是结点)【依靠运算符的重载实现】 ++it; } cout << endl; //此时虽然没有暴露结构,但是可以输出 } void test_vector() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); //迭代器方法: vector<int>::iterator it = v.begin();//定义个对象it 左闭右开[begin,end) while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; //vector重载了[],所以还有使用[]的方法 这是它与list不同的地方 for (size_t i = 0; i < v.size(); ++i) { cout << v[i] << " "; } cout << endl; }
Test.cpp
#include <iostream> using namespace std; #include "vector_list.h" int main() { //test_list(); test_vector(); system("pause"); return 0; }
(三)const迭代器
迭代器时可读可写的,但有时只允许读。
void print_list(const list<int>& l) { list<int>::iterator it = l.begin(); while (it != l.end()) { if (*it % 2) //此步骤为了让所有奇数乘以2 { *it *= 2 ; //此时再写就编不过 } ++it; } cout << endl; }
如上定义print_list函数,用
list<int> l1;
print_list(l1); 语句去调用时出错。
错误在于
list<int>::iterator it = l.begin();
语句,因为l是const对象,而begin()为非const成员函数,返回值赋不过去。
但加
const改为list<int>::const iterator it = l.begin();
后仍然无法编过,是因为const不允许写,而*it *=2; 进行了写操作。
所以,三种迭代器的作用分别为:
- 普通 可读可写 正向
- 反向 可读可写 反向
- const 只读 可正可反
(四)list接口的使用
- max_size() 【返回整型取满再除以单个对象的大小】
- front back 【访问头和尾】
- assign(10,5) 【赋值 分配 把原先的丢掉,给成10个5】
- emplace_front 【头插,双引用,有时候会更高效】
- emplace_back 【尾插】
- push_front 【头插】
- pop_front 【头删】
- push_back 【尾插】
- pop_back 【尾删】
- insret 【在一个位置之前插入一个元素进行扩张】
- erase 【删除】(注意迭代器失效)
list的查功能在算法中实现。