STL学习总结

目录

  • Reference
  • 一、STL简介
  • 二、容器
    • 2.1 顺序容器
      • 2.1.1 vector
      • 2.2.2 deque
      • 2.1.3 list
      • 2.1.4 forward_list
      • 2.1.5 array
      • 2.1.6 顺序容器的选择
      • 2.1.7 插入迭代器
      • 2.18 顺序容器适配器
    • 2.2 关联容器
      • 2.2.1 map介绍
      • 2.2.2 set介绍
      • 2.2.3 multimap & multiset
  • 三、迭代器
    • 3.1 迭代器介绍
    • 3.2 迭代器分类
    • 3.3 迭代器支持的操作
    • 3.4 迭代器使用示例
  • 四、函数对象
    • 4.1 自定义函数对象作为算法参数
    • 4.2 标准函数对象作为算法参数
  • 五、算法
  • 六、扩展
    • 6.1 Vector与数组的异同点
    • 6.2 C++ vector和list的区别
    • 6.3 常见面试题

Reference

  • C++ STL编程
  • STL教程:C++ STL快速入门(非常详细)
  • [STL基础]STL概述+总结
  • STL学习笔记— —STL简述
  • C++ STL(面试复习整理)
  • C++ map用法总结
  • C++关联容器
  • C++ set用法总结
  • 关于c++中stack、queue和priority_queue的介绍

一、STL简介

STL就是Standard Template Library,标准模板库。STL是泛型编程的实例,用到的技术就是类模板和函数模板。STL的一个重要特点是数据结构和算法的分离

模板
所谓模板是一种使用无类型参数来产生一系列函数或类的机制。通过模板可以产生类或函数的集合,使它们操作不同的数据类型,从而避免需要为每一种数据类型产生一个独立的类或函数

泛型程序设计

  • 编写不依赖于具体数据类型的程序。
  • 把算法从特定的书结构中抽象出来,成为通用的。
  • C++ 的模板为泛型程序设计奠定了关键基础。
    STL学习总结_第1张图片

STL学习总结_第2张图片
STL学习总结_第3张图片

STL学习总结_第4张图片
STL学习总结_第5张图片

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main() {
     
    const int N = 5;
    vector<int> s(N);	//定义一个大小为N的向量容器
    //从标准输入读入向量容器的内容
    for (int i = 0; i < N; i++)
        cin >> s[i];
    //输出向量容器中每个元素的相反数
    transform(s.begin(), s.end(), ostream_iterator<int>(cout, " "), negate<int>());
    cout << endl;
    return 0;
}

二、容器

STL学习总结_第6张图片
STL学习总结_第7张图片
STL学习总结_第8张图片

2.1 顺序容器

Reference
C++序列式容器(STL序列式容器)是什么

所谓序列容器,即以线性排列(类似普通数组的存储方式)来存储某一指定类型(例如 int、double 等)的数据,需要特殊说明的是,该类容器并不会自动对存储的元素按照值的大小进行排序。

需要注意的是,序列容器只是一类容器的统称,并不指具体的某个容器,序列容器大致包含以下几类容器:

  • array(数组容器):表示可以存储 N 个 T 类型的元素,是 C++ 本身提供的一种容器。此类容器一旦建立,其长度就是固定不变的,这意味着不能增加或删除元素,只能改变某个元素的值;
  • vector(向量容器):用来存放 T 类型的元素,是一个长度可变的序列容器,即在存储空间不足时,会自动申请更多的内存。使用此容器,在尾部增加或删除元素的效率最高(时间复杂度为 O(1) 常数阶),在其它位置插入或删除元素效率较差(时间复杂度为 O(n) 线性阶,其中 n 为容器中元素的个数);
  • deque(双端队列容器):和 vector 非常相似,区别在于使用该容器不仅尾部插入和删除元素高效,在头部插入或删除元素也同样高效,时间复杂度都是 O(1) 常数阶,但是在容器中某一位置处插入或删除元素,时间复杂度为 O(n) 线性阶;
  • list(链表容器):是一个长度可变的、由 T 类型元素组成的序列,它以双向链表的形式组织元素,在这个序列的任何地方都可以高效地增加或删除元素(时间复杂度都为常数阶 O(1)),但访问容器中任意元素的速度要比前三种容器慢,这是因为 list 必须从第一个元素或最后一个元素开始访问,需要沿着链表移动,直到到达想要的元素。
  • forward_list(正向链表容器):和 list 容器非常类似,只不过它以单链表的形式组织元素,它内部的元素只能从第一个元素开始访问,是一类比链表容器快、更节省内存的容器。

2.1.1 vector

STL学习总结_第9张图片
STL学习总结_第10张图片
STL学习总结_第11张图片

2.2.2 deque

STL学习总结_第12张图片
STL学习总结_第13张图片
STL学习总结_第14张图片
STL学习总结_第15张图片

奇偶排序示例:

//10_5.cpp
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main() {
     
    istream_iterator<int> i1(cin), i2;	//建立一对儿输入流迭代器
    vector<int> s1(i1, i2);	//通过输入流迭代器从标准输入流中输入数据
    sort(s1.begin(), s1.end());			//将输入的整数排序
    deque<int> s2;
    //以下循环遍历s1
    for (vector<int>::iterator iter = s1.begin(); iter != s1.end(); ++iter) {
     
        if (*iter % 2 == 0)	//偶数放到s2尾部
            s2.push_back(*iter);
        else				//奇数放到s2首部
            s2.push_front(*iter);
    }
    //将s2的结果输出
    copy(s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    return 0;
}

2.1.3 list

  • C++ List的用法(整理)
  • C ++ list 用法整理(官网例子)

STL学习总结_第16张图片
STL学习总结_第17张图片
STL学习总结_第18张图片

#include 
#include 
#include 
#include 
using namespace std;

int main() {
     
    string names1[] = {
      "Alice", "Helen", "Lucy", "Susan" };
    string names2[] = {
      "Bob", "David", "Levin", "Mike" };
    list<string> s1(names1, names1 + 4); //用names1数组的内容构造列表s1
    list<string> s2(names2, names2 + 4); //用names2数组的内容构造列表s2

    //将s1的第一个元素放到s2的最后
    s2.splice(s2.end(), s1, s1.begin());
    list<string>::iterator iter1 = s1.begin(); //iter1指向s1首
    advance(iter1, 2); //iter1前进2个元素,它将指向s1第3个元素
    list<string>::iterator iter2 = s2.begin();  //iter2指向s2首
    ++iter2; //iter2前进1个元素,它将指向s2第2个元素
    list<string>::iterator iter3 = iter2; //用iter2初始化iter3
    advance(iter3, 2); //iter3前进2个元素,它将指向s2第4个元素
    //将[iter2, iter3)范围内的结点接到s1中iter1指向的结点前
    s1.splice(iter1, s2, iter2, iter3);

    //分别将s1和s2输出
    copy(s1.begin(), s1.end(), ostream_iterator<string>(cout, " "));
    cout << endl;
    copy(s2.begin(), s2.end(), ostream_iterator<string>(cout, " "));
    cout << endl;
    return 0;
}

2.1.4 forward_list

STL学习总结_第19张图片

2.1.5 array

STL学习总结_第20张图片

2.1.6 顺序容器的选择

STL学习总结_第21张图片
STL学习总结_第22张图片
STL学习总结_第23张图片

2.1.7 插入迭代器

STL学习总结_第24张图片

2.18 顺序容器适配器

STL学习总结_第25张图片

STL学习总结_第26张图片
STL学习总结_第27张图片

STL学习总结_第28张图片
STL学习总结_第29张图片

2.2 关联容器

STL学习总结_第30张图片

关联容器支持高效的关键字查找和访问,两个主要的关联容器是map和set,map中的元素是一些关键字-值(key-value)对:关键字起到索引的作用,值表示与索引相关联的数据。set中每个元素只包含一个关键字:set支持高效的关键字查询操作,检查一个给定关键字是否在set中。

标准库提供了8个关联容器,这8个容器的不同体现在关键字是否能重复,是否按顺序保存元素,这里的顺序不是指元素添加顺序,而是关键字的比较顺序,multi表示关键字可重复,unordered表示元素是无序保存的。

  • map

  • set

  • multi map,

  • multi set,

  • unordered_map

  • unordered_set

  • unordered_multi map

  • unordered_multi set

关键字类型的要求
对于有序容器,关键字类型必须定义元素比较的方法,默认情况下标准库使用关键字类型的<运算符来比较,也可以在创建有序容器时自定义比较操作函数。
STL学习总结_第31张图片
STL学习总结_第32张图片
STL学习总结_第33张图片
STL学习总结_第34张图片

2.2.1 map介绍

STL学习总结_第35张图片

  • map的基本操作函数:
    C++ maps是一种关联式容器,包含“关键字/值”对

    begin() 返回指向map头部的迭代器
    clear() 删除所有元素
    count() 返回指定元素出现的次数
    empty() 如果map为空则返回true
    end() 返回指向map末尾的迭代器
    equal_range() 返回特殊条目的迭代器对
    erase() 删除一个元素
    find() 查找一个元素
    get_allocator() 返回map的配置器
    insert() 插入元素
    key_comp() 返回比较元素key的函数
    max_size() 返回可以容纳的最大元素个数
    rbegin() 返回一个指向map尾部的逆向迭代器
    rend() 返回一个指向map头部的逆向迭代器
    size() 返回map中元素的个数
    swap() 交换两个map
    lower_bound() 返回键值>=给定元素的第一个位置
    upper_bound() 返回键值>给定元素的第一个位置
    value_comp() 返回比较元素value的函数

2.2.2 set介绍

STL学习总结_第36张图片

2.2.3 multimap & multiset

STL学习总结_第37张图片

#include 
#include 
#include 
#include 
using namespace std;

int main() {
     
    multimap<string, string> courses;
    typedef multimap<string, string>::iterator CourseIter;

    //将课程上课时间插入courses映射中
    courses.insert(make_pair("C++", "2-6"));
    courses.insert(make_pair("COMPILER", "3-1"));
    courses.insert(make_pair("COMPILER", "5-2"));
    courses.insert(make_pair("OS", "1-2"));
    courses.insert(make_pair("OS", "4-1"));
    courses.insert(make_pair("OS", "5-5"));
    //输入一个课程名,直到找到该课程为止,记下每周上课次数
    string name;
    int count;
    do {
     
        cin >> name;
        count = courses.count(name);
        if (count == 0)
            cout << "Cannot find this course!" << endl;
    } while (count == 0);
    //输出每周上课次数和上课时间
    cout << count << " lesson(s) per week: ";
    pair<CourseIter, CourseIter> range = courses.equal_range(name);
    for (CourseIter iter = range.first; iter != range.second; ++iter)
        cout << iter->second << " ";
    cout << endl;

    return 0;
}

三、迭代器

3.1 迭代器介绍

STL学习总结_第38张图片

3.2 迭代器分类

STL学习总结_第39张图片

STL学习总结_第40张图片

//10_2.cpp
#include 
#include 
#include 
using namespace std;

//求平方的函数
double square(double x) {
     
    return x * x;
}

int main() {
     
    //从标准输入读入若干个实数,分别将它们的平方输出
    transform(istream_iterator<double>(cin), istream_iterator<double>(),
              ostream_iterator<double>(cout, "\t"), square);
    cout << endl;
    return 0;
}

3.3 迭代器支持的操作

STL学习总结_第41张图片
STL学习总结_第42张图片
STL学习总结_第43张图片

3.4 迭代器使用示例

//10_3.cpp
#include 
#include 
#include 
#include 
using namespace std;

//将来自输入迭代器p的n个T类型的数值排序,将结果通过输出迭代器result输出
template <class T, class InputIterator, class OutputIterator>
void mySort(InputIterator first, InputIterator last, OutputIterator result) {
     
	//通过输入迭代器p将输入数据存入向量容器s中
	vector<T> s;
	for (;first != last; ++first)
		s.push_back(*first);
	//对s进行排序,sort函数的参数必须是随机访问迭代器
	sort(s.begin(), s.end());
	//将s序列通过输出迭代器输出
	copy(s.begin(), s.end(), result);
}

int main() {
     
	//将s数组的内容排序后输出
	double a[5] = {
      1.2, 2.4, 0.8, 3.3, 3.2 };
	mySort<double>(a, a + 5, ostream_iterator<double>(cout, " "));
	cout << endl;
	//从标准输入读入若干个整数,将排序后的结果输出
	mySort<int>(istream_iterator<int>(cin), istream_iterator<int>(), ostream_iterator<int>(cout, " "));
	cout << endl;
	return 0;
}

四、函数对象

STL学习总结_第44张图片
STL学习总结_第45张图片

4.1 自定义函数对象作为算法参数

STL学习总结_第46张图片

//10_13.cpp
#include    
#include 	//包含数值算法头文件
using namespace std;

int mult(int x, int y) {
      return x * y; };	//定义一个普通函数
int main() {
     
	int a[] = {
      1, 2, 3, 4, 5 };
	const int N = sizeof(a) / sizeof(int);
	cout << "The result by multipling all elements in a is "
		<< accumulate(a, a + N, 1, mult)	//将普通函数mult传递给通用算法
		<< endl;
	return 0;
}

STL学习总结_第47张图片

//10_14.cpp
#include 
#include 	//包含数值算法头文件
using namespace std;

class MultClass	{
       //定义MultClass类
public:
	int operator() (int x, int y) const {
      return x * y; }	//重载操作符operator()
};

int main() {
     
	int a[] = {
      1, 2, 3, 4, 5 };
	const int N = sizeof(a) / sizeof(int);
	cout << "The result by multipling all elements in a is "
		<< accumulate(a, a + N, 1, MultClass())	//将类multclass传递给通用算法
		<< endl;
	return 0;
}

STL学习总结_第48张图片

4.2 标准函数对象作为算法参数

STL学习总结_第49张图片

//10_15.cpp
#include    
#include    //包含数值算法头文件
#include   //包含标准函数对象头文件
using namespace std;	
int main() {
     
	int a[] = {
      1, 2, 3, 4, 5 };
	const int N = sizeof(a) / sizeof(int);
	cout << "The result by multipling all elements in A is "
		<< accumulate(a, a + N, 1, multiplies<int>()) //将标准函数对象传递给通用算法
		<< endl;
	return 0;
}

STL学习总结_第50张图片

//10_16.cpp
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main() {
     
    int intArr[] = {
      30, 90, 10, 40, 70, 50, 20, 80 };
    const int N = sizeof(intArr) / sizeof(int);
    vector<int> a(intArr, intArr + N);

    cout << "before sorting:" << endl;
    copy(a.begin(), a.end(), ostream_iterator<int>(cout, "\t"));
    cout << endl;

    sort(a.begin(), a.end(), greater<int>());

    cout << "after sorting:" << endl;
    copy(a.begin(), a.end(), ostream_iterator<int>(cout, "\t"));
    cout << endl;
    return 0;
}

STL学习总结_第51张图片
STL copy()函数用法

#include 
#include 
#include 
 
using namespace std;
 
int main()
{
     
    int src[]={
     1,2,3,4,5,6,7};
    //vector srcVec;
    //srcVec.resize(7);
 
    vector<int> srcVec(src,src+7);          //注意!7为长度
    ostream_iterator<int> ofile(cout," ");
    //将数值复制到vector里,参数依次是开始,结束,vector数组的开始
    //(看起来src+7越界了)src+7,表示结束,srcVec.end()相当于src+7
    copy(src,src+7,srcVec.begin());
    
    cout<<"srcVec contains:\n";
 
    //将数值复制到输出流中,参数依次是开始,结束,输出流
    copy(srcVec.begin(),srcVec.end(),ofile);
 
    cout<<endl;
 
    //将数组向左移动两位
    copy(src+2,src+7,src);
    cout<<"shifting array sequence left by 2"<<endl;
    copy(src,src+7,ofile);
    cout<<endl;
 
 
    //另一种方法,注意观察copy()中第二个参数
    //srcVec.end()相当于src+7
    //将数组向左移动两位
    copy(srcVec.begin()+2,srcVec.end(),srcVec.begin());
    cout<<"shifting array sequence left by 2"<<endl;
    copy(srcVec.begin(),srcVec.end(),ofile);
    cout<<endl;
    return 0;
}

五、算法

STL学习总结_第52张图片

六、扩展

6.1 Vector与数组的异同点

数组是c++中类似vector的数据结构,它们都可以对一种类型进行储存,既都是容器。虽说两者有相似之处,但也有显著的区别,c++ primer的作者说到,在实际的编程中,我们作为程序员应该避免用到低级数组和指针,而更应该多用高级的vector和迭代器。在程序强调速度的情况下,我们程序员可以在类类型的内部使用数组和指针。下面我对vector和数组进行了总结。

vector扩容原理概述

  • 新增元素:Vector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,在插入新增的元素;
  • 对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了 ;
  • 初始时刻vector的capacity为0,塞入第一个元素后capacity增加为1;
  • 不同的编译器实现的扩容方式不一样,VS2015中以1.5倍扩容,GCC以2倍扩容。

当面试官问我们vector扩容机制时,他想问什么?

#include
#include
using namespace std;
int main()
{
     
    vector<int> vec;
    cout << vec.capacity() << endl;
    for (int i = 0; i<10; ++i)
    {
     
        vec.push_back(i);
        cout << "size: " << vec.size() << endl;
        cout << "capacity: " << vec.capacity() << endl;
    }
    system("pause");
    return 0;
}

两者的相同点如下

  • 都是对同一种类型的数据进行储存。
  • 都可以用下标操作进行处理。
  • 都可以用迭代器进行操作(在c++中每个容器都配有各自的迭代器,数组也是种容器)

两者的区别如下

  • vector可以用size获取vector的长度,而数组不可以。
  • vector长度不固定,可以随时增加,而数组长度固定,在定义之后就不可以更改。
  • vector可以在末尾增加元素(用push_back),而数组不能增加在长 度以外的长度。
  • 可以确定长度,节约空间,不能确定长度,必须在定义时定义一个很大的空间留给数组,造成内存的浪费。

6.2 C++ vector和list的区别

  • vector和数组类似,拥有一段连续的内存空间,而list是由双向链表实现的,因此内存空间是不连续的。
  • vector支持高效的随机存取,时间复杂度为o(1),而list随机存取效率很低,时间复杂度为o(n),只能通过指针访问。
  • vector只有在尾部插入和添加加的效率高,而list在任何位置都能高效地进行插入和删除。

6.3 常见面试题

STL标准库常见面试题(一)
C++STL常见面试题

你可能感兴趣的:(笔记,笔试面经,STL,关联容器)