泛化编程 day03
Posted 达少Rising
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了泛化编程 day03相关的知识,希望对你有一定的参考价值。
回顾:
泛化编程 day01
泛化编程 day02
六、STL(标准模板库)
1、STL容器介绍
-
1)STL的概念全称为Standard Template Library(标准模板库)
-
2)STL的作用
- 首先STL并不是语言的一部分(一开始并没有)它就是一个工具库,没有这个工具时程序员写程序都要自己做容器(例如:数据结构中的链表,堆栈等)
- STL模板内部使用模板使操作更加泛化,STL内部两大部分构成:容器和泛型算法
-
3)数组和链表优缺点
- 数组:
- 优点:随机访问,速度快效率高
- 缺点:插入删除不方便,效率低(内存空间分布的限制)
- 链表:
- 优点:插入删除操作方便,效率高
- 缺点:随机访问不方便效率低,往往就是通向在遍历过程中对给定的条件进行检测。
- 总结:STL模板库中提供的容器类,结合了数组和链表的优缺点,使用户从诸如内存管理的细节中得以解脱(对数组和链表的操作进行了封装)
- 数组:
-
4)十大容器
- 向量(vector):类似数组(内部是线性存储)支持下标访问,在尾部添加和删除元素效率高,中间可以执行添加删除操作但效率低;
- 双端队列(deque):支持下标访问(头尾两端都支持添加/删除操作);
- 列表(list):在任何位置添加和删除操作都很方便,不支持下标访问;
- 堆栈(stack):支持在一端存储和提取元素;
- 队列(queue):支持从前端提取,后端压入元素;
- 优先队列(priority_queue):类似队列,但所提取的是具有最高优先级的元素(默认大者优先)
- 映射(map):以key-value对 的形式存储数据,以key的升序排列,key唯一(内部结构是红黑树);
- 多重映射(multimap):允许key重复出现的映射;
- 集合(set):没有val的映射;
- 多重集合(multiset):没有value的多重映射。
-
5)容器的分类
- 线性容器:(向量,双端队列,列表)这类容器元素按照线性顺序排列,必须支持某种形式的next操作,以便从一个元素移动到下一个元素(迭代)
- 适配器容器:(堆栈,队列,优先队列)这类容器是对线性容器的一些接口加以屏蔽的产物
- 关联容器:(映射,多重映射,集合,多重集合)这类容器根据一个元素相关联的key来存储或提取数据元素,存储是以key-value对的形式,按照key的升序(二叉树存储)
-
6)容器的共同特点
- 所有容器都支持拷贝构造和拷贝赋值
- 相同类型的两个容器之间可以通过
==
进行相等性判断 - 容器存储的为数据的副本这也意味着存入容器中的对象应支持拷贝构造和拷贝赋值
- 通常情况下被存放到容器中的对象应支持无参构造
七、十大容器
1、向量(vector)
-
1)成员函数
- front()/back()/insert()/erase()
- push_back()/pop_back()/empty()/clear()
- size()向量维护元素个数
- resize()设置向量元素个数
- capacity()获取向量容量
- reserve()设置向量的容量
-
2)向量的初始化
- 向量中的元素被存储在一段连续的内存空间中通过下标访问向量元素的效率与数组相当;
- 向量维护的内存空间回随着新元素的增加而自动增加;
- 内存空间多的连续性不会妨碍向量元素的增加,如果内存空间无法满足新元素的增加,向量会开辟新的足够的连续内存空间,并把原内存空间的数据复制到新的内存空间,释放原内存空间;
- 向量的增加会伴随着内存的分配和释放,元素复制和销毁等额外开销;
- 如果能够在创建向量时,合理分配一些空间将很大程度上缓解这些额外的开销。
eg:01vectorinit.cpp
#include <iostream>
#include <vector>
using namespace std;
void print(string const& str, vector<int>& v)
{
cout << str << endl;
cout << "向量的容量:" << v.capacity() << endl;
for(size_t i=0; i<v.capacity(); i++){
cout << v[i] << " ";
}
cout << endl;
cout << "向量的大小:" << v.size() << endl;
for(size_t i=0; i<v.size(); i++){
cout << v[i] << ' ';
}
cout << endl << "------------" <<endl;
}
int main(void)
{
vector<int> v1;//沒有維護任何的內存空間
print("v1:",v1);
vector<int> v2(10);//向量容量爲10,大小也爲10,存儲的數據都爲0
print("v2:", v2);
vector<int> v3(10, 5);//向量容量爲10,大小也爲10,存儲的數據都爲5
print("v3:", v3);
v3.push_back(100);//增加一個數據容量,容量增加不止一個
print("after v3 add a new data:", v3);
v3.pop_back();
print("after v3 delete a data:", v3);
v3.push_back(500);
print("v3 add data again:", v3);
return 0;
}
eg:02vector.cpp
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
class Student
{
public:
Student(string const& name="", int const& age=0):
m_name(name), m_age(age){
cout << "缺省構造了:" << m_name << "(" << this << ")" << endl;
}
Student(Student const& that):m_name(that.m_name), m_age(that.m_age){
cout << "用" << that.m_name << "(" << &that << ")" << "拷貝構造了:"
<< m_name << "(" << this << ")" << endl;
}
~Student(){
cout << "析构了:" << m_name << "(" << this << ")" << endl;
}
private:
string m_name;
int m_age;
};
int main(void)
{
vector<Student> vs;
vs.reserve(10);
vs.push_back(Student("Adair"));
vs.push_back(Student("Rising"));
vs.push_back(Student("weeks"));
getchar();
return 0;
}
- 3)迭代器
- 顺序迭代器:一次只能向后或向前迭代一步,只支持
++
和--
运算; - 随即迭代器:既能一次向前或向后迭代一步,也可以迭代多步,除了支持
++
和--
,也支持对整数的加减运算,除了向量和双端队列以及优先队列随即迭代器以外,其余容器只支持顺序迭代器; - 正向迭代器:起始迭代器指向向量第一个元素位置,终止迭代器指向向量
最后一个元素的下一个位置
,增操作向容器的尾部移动,减操作向容器的首部移动; - 反向迭代器:起始迭代器指向向量最后一个元素位置,终止迭代器指向向量
第一个元素的前一个位置
,增操作向容器的首部移动,减操作向容器的尾部移动。 - 四个迭代器类:
- iterator/const_iterator
- reverse_iterator/const_reverse_iterator
- 八个迭代器对象:
- begin()/end()
- begin()const/end()const
- rebegin()/rend()
- rbegin()const/rend()const
- 顺序迭代器:一次只能向后或向前迭代一步,只支持
- 4)迭代器的使用
- 任何可能导致容器结构发生变化的函数被调用后,先前获取的迭代器可能失效,重新初始化迭代器再使用才是安全的。
eg:01vector.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void print(string const& str, vector<T>& v){
cout << str << endl;
typedef typename vector<T>::iterator IT;
for(IT it=v.begin(); it!=v.end(); ++it)
cout << *it << ' ';
cout << endl << "---------" << endl;
}
class CMP
{
public:
bool operator()(int const& a, int const& b)const{
return a < b;
}
};
int main(void)
{
vector<int> vi;
for(int i=0; i<10; i++){
vi.push_back(10-i);
}
print("添加节点后:", vi);
vi.insert(vi.begin(), 300);
print("在迭代器指向位置添加节点后:", vi);
vi.erase(vi.begin());
print("删除迭代器指向的节点后:",vi);
typedef vector<int>::iterator IT;
IT fit = find(vi.begin(), vi.end(), 5);
if(fit!=vi.end())
vi.erase(fit);
print("找到元素5并删除后:", vi);
//sort(vi.begin(), vi.end());//内部用“<”s实现排序
CMP cmp;
sort(vi.begin(), vi.end(), cmp);//内部用比较器(cmp)排序
print("排序后:", vi);
return 0;
}
eg:02vector.cpp
include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Student
{
public:
Student(string const& name="",int const& age=0):m_name(name),m_age(age){}
friend ostream& operator<<(ostream& os, Student const& s){
os << s.m_name << ","<< s.m_age;
return os;
}
bool operator==(Student const& that){
return m_name==that.m_name && m_age==that.m_age;
}
bool operator<(Student const& that){
return m_age < that.m_age;
}
private:
string m_name;
int m_age;
};
template<class T>
void print(string const& str, vector<T>& v){
cout << str << endl;
typedef typename vector<T>::iterator IT;
for(IT it=v.begin(); it!=v.end(); ++it)
cout << *it << ' ';
cout << endl << "---------" << endl;
}
emplate<class T>
class CMP
{
public:
bool operator()(T const& a, T const& b)const{
return a < b;
}
/*
public:
bool operator()(int const& a, int const& b)const{
return a < b;
}
bool operator()(Student const& a, Student const& b)const{
return a < b;
}
*/
};
int main(void)
{
/*
vector<int> vi;
for(int i=0; i<10; i++){
vi.push_back(10-i);
}
print("添加节点后:", vi);
vi.insert(vi.begin(), 300);
print("在迭代器指向位置添加节点后:", vi);
vi.erase(vi.begin());
print("删除迭代器指向的节点后:",vi);
typedef vector<int>::iterator IT;
IT fit = find(vi.begin(), vi.end(), 5);
if(fit!=vi.end())
vi.erase(fit);
print("找到元素5并删除后:", vi);
//sort(vi.begin(), vi.end());//内部用“<”s实现排序
CMP<int> cmp;
sort(vi.begin(), vi.end(), cmp);//内部用比较器(cmp)排序
print("排序后:", vi);
*/
vector<Student> vs;
vs.push_back(Student("weeks", 28));
vs.push_back(Student("adair", 25));
vs.push_back(Student("rising", 26));
vs.push_back(Student("zhou", 23));
vs.push_back(Student("ten", 28));
vs.push_back(Student("cent", 29));
print("添加节点后:", vs);
vs.insert(vs.begin(), Student("da", 25));
print("在迭代器制定的位置添加节点后:", vs);
vs.erase(vs.begin());
print("删除迭代器指向的节点后:", vs);
typedef vector<Student>::iterator IT;
IT fit = find(vs.begin(), vs.end(), Student("zhou", 23));
if(fit!=vs.end())
vs.erase(fit);
print("找到zhou并删除后:", vs);
//sort(vs.begin(), vs.end());
CMP<Student> cmp;
sort(vs.begin(), vs.end(), cmp);
print("排序后:",vs);
return 0;
}
- 5)查找
template<class IT, class value_type> IT find(IT begin, IT end,value_type& key)//成功返回第一个匹配元素的迭代器,失败返回第二个参数
- 6)排序
//使用内部的sort函数 template<class IT>void sort(IT begin, IT end); //自定义比较器比较 template<class IT, class LESS> void sort(IT begin, IT end, LESS LSEE cmp);
2、双端队列
- 1)和向量差别就是首尾两端同样都是开放的,因此他同时提供了首尾两端增删元素的接口
- 2)没有提供设置/获取容量的函数,设置和获取容器大小的函数存在
eg:03deque.cpp
#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;
template<class T>
void print(string const& str, deque<T>& d){
cout << str << endl;
typedef typename deque<T>::iterator IT;
for(IT it=d.begin(); it!=d.end(); ++it){
cout << *it << ' ';
}
cout << endl << "-----------" << endl;
}
template<class T>
class CMP
{
public:
bool operator()(T const& a, T const& b){
return a > b;
}
};
int main(void)
{
deque<int> di;
for(int i=0; i<5; i++){
di.push_front(10-i);
}
for(int i=0; i<5; i++){
di.push_back(11+i);
}
print("添加节点后:", di);
di.pop_front();
di.pop_back();
print("删除头尾节点后:", di);
di.insert(++di.begin(), 500);
print("在迭代器指向的位置添加节点后:",di);
di.erase(di.begin());
print("删除迭代器指向的节点后:", di);
typedef deque<int>::iterator IT;
IT fit = find(di.begin(), di.end(), 10);
if(fit!=di.end())
di.erase(fit);
print("找到元素10并删除后:",di);
sort(di.begin(), di.end());
print("排序后:", di);
CMP<int> cmp;
sort(di.begin(), di.end(), cmp);
print("比较器排序后:", di);
return 0;
泛化编程 day02