STL的一些知识点整理

标准模板库(STL)

  • 常用数据结构和算法的模板的集合

  • 有了STL,不必再从头写大多的标准数据结构和算法,并且可以获得非常高的性能,节省了大量的时间和精力。

泛型程序设计---使用模板的程序设计法

  • 将一些常用的数据结构(如链表、数组、二叉树)和算法(如排序、查找)写成模板,以后则不论数据结构里放的是什么对象,算法针对什么样的对象,则都不必重新实现数据结构,重新编写算法。

模板分类:

  • 函数模板

    • 是独立类型的函数

    • 可产生函数的特定版本

  • 类模板

    • 跟类相关的模板--vector

    • 可产生类对特定类型的版本,如vector<int>

STL中的基本概念:

  • 容器———可容纳各种数据类型的数据结构

  • 迭代器————可依次存取容器中元素的智能指针(如int a[100]是个容器,而int* 类型的指针变量就可以作为迭代器,可以为 这个容器编写一个排序的算法)

  • 算法algorithm

    • 用来操作容器中的元素的函数模板。sort()---对一个vector中的数据进行排序;find()---搜索一个list中的对象

    • 函数本身与他们操作的数据的结构和类型无关,在从简单数组到高复杂容器的任何数据结构上使用。

容器:可以用于存放各种类型的数据的数据结构

  • 顺序容器(将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素)(元素的插入位置与元素的值无关)

    • vector:后部插入/删除,直接访问任何元素;动态数组,随机存取任何元素都能在常数时间完成,在尾端增删元素具有较佳的性能。

    • deque:前/后部插入/删除,直接访问,随机存取;性能次于vector;

    • list:     双向链表,任意位置插入、删除;在两端增删元素具有较佳的性能,不支持随机存取;双向不随机

  • 关联容器(支持通过键来高效的查找和读取元素(map/set))(元素是排序的,插入任何元素都按相应的排序准则来确定其位置。特点:在查找时具有非常好的性能)

    • set:快速查找,无重复元素

    • map:一对一映射,无重复元素,基于关键字查找 

  • 容器适配器

    • stack(后进先出)

    • queue(先进先出)

容器的共有成员函数:

1)所有标准库容器共有的成员函数:

  • 相当于按词典顺序比较两个容器大小的运算符:  =, < , <= , >  , >=, == , !=

  • empty : 判断容器中是否有元素

  • max_size: 容器中最多能装多少元素

  • size:   容器中元素个数

  • swap: 交换两个容器的内容

    若两容器长度相同、所有元素相等,则两个容器就相等,否则为不等。

    若两容器长度不同,但较短容器中所有元素都等于较长容器中对应的元素,则较短容器小于另一个容器

    若两个容器均不是对方的子序列,则取决于所比较的第一个不等的元素

2)只在第一类容器中的函数

  • begin  返回指向容器中的第一个元素的迭代器

  • end    返回指向容器中最后一个元素后面的位置的迭代器

  • erase   从容器中删除一个或几个元素

  • clear    从容器中删除所有的元素

迭代器:

1.定义:

  • 提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。

  • 用于指向第一类容器的元素,有const和非const两种

2.用法与指针相似

  • 通过迭代器可以读取它指向的元素;

  • 通过非const迭代器还能修改其指向的元素;

3.定义一个容器类的迭代器的方法

  • 容器类名::iterator  变量名

  • 容器类名::const_iterator  变量名

#include <vector>
#include <iostream>
using namespace std;
int main()  {
  vector<int> v; //一个存放int元素的向量,一开始里面没有元素
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);
  v.push_back(4);
  vector<int>::const_iterator i;   //常量迭代器
  for( i = v.begin(); i != v.end(); i ++ )
  cout << * i << ",";
  cout << endl;
  vector<int>::reverse_iterator r;  //反向迭代器
  for( r = v.rbegin(); r != v.rend(); r++ )
  cout << * r << ",";
  cout << endl;
  vector<int>::iterator j;   //非常量迭代器
  for( j = v.begin();j != v.end();j ++ )
  * j =  100;
  for( i = v.begin();i != v.end();i++ )
  cout << * i << ",";
}

不同迭代器所能进行的操作(功能)

* 所有迭代器: ++p, p ++

* 输入迭代器: * p, p = p1, p == p1 , p!= p1

* 输出迭代器: * p, p = p1

* 正向迭代器: 上面全部

* 双向迭代器: 上面全部,--p, p --,

* 随机访问迭代器: 上面全部以及:

    *   p+= i, p -= i,

    *   p + i: 返回指向 p 后面的第i个元素的迭代器

    *   p - i: 返回指向 p 前面的第i个元素的迭代器

    * p[i]:  p 后面的第i个元素的引用

    *   p < p1, p <= p1, p > p1, p>= p1

&&stack、queue、priority_queue不支持迭代器

vector的迭代器是随机迭代器,故遍历vector可以有以下几种做法:

vector<int>v(100);
for(int i=0;i<v.size();i++)
    cout<<v[i];
vector<int>::const_iterator ii;
for(ii=v.begin;ii!=v.end();ii++)
    cout<<*ii;
ii=v.begin();
while(ii<v.end())
{
    cout<<*ii;
    ii=ii+2;//间隔一个输出
}

算法简介

      STL中提供能在各种容器中通用的算法,如插入、删除、查找、排序等。

  • 算法就是函数模板;

  • 算法通过迭代器来操纵容器中的元素;许多算法需要两个参数,即其实元素的迭代器和终止元素的后面一个元素的迭代器。

  • 有的算法返回一个迭代器。如find()算法:在容器中查找一个元素,并返回一个指向该元素的迭代器;

  • 算法可以处理容器,也可以处理C语言的数组。

算法分类

  • 变化序列算法

    • copy、remove、replace、random_shuffle、swap等

    • 会改变容器

  • 非变化序列算法

    • equal、find、mismatch、count、search等

  • 排序相关算法

    • 以上函数模板都在<algorithm>中定义

    • 此外还有其他算法,比如<numeric>中的算法

算法示例:find()

  template<class InIt, class T>

  InIt find(InIt first, InIt last, const  T&val);

  • first和last这两个参数都是容器的迭代器,他们给出了容器中的查找区间起点和终点;

  • 区间左闭右开

  • val是要查找的元素的值;

  • 函数返回值是一个迭代器。如果找到则该迭代器指向被找到的元素。否则,指向查找区间终点。


顺序容器

   共同操作:

  • front():返回容器中第一个元素的引用

  • back():返回容器中最后一个元素的引用

  • push_back():在容器末尾增加新元素;

  • pop_back():删除容器末尾的元素;

vector示例

  • 支持随机访问迭代器,所有的STL算法都能对vector进行操作;

  • 随机访问时间为常数。在尾部添加速度很快,在中间插入很慢。实际是动态数组。

--->copy (v.begin(),v.end(), output): 导致v的内容在 cout上输出、


关于ostream_iterator, istream_iterator的例子:

istream_iterator<int>inputInt(cin);
int n1,n2;
n1=*inputInt;//读入n1;
inputInt++;
n2=*inputInt;//读入n2;
cout<<n1<<","<<n2<<endl;
ostream_iterator<int>outputInt(cout);
*outputInt=n1+n2;
cout<<endl;
int a[5]={1,2,3,4,5};
copy(a,a+5,outputInt);//输出整个数组

list容器

    不支持随机存取,在任何位置插入删除都是常数时间,除了具有所有顺序容器都有的成员函数外,还有:

  • push_front:在前面插入

  • pop_front:删除前面的元素

  • sort:排序(list不支持STL的算法sort)

  • remove:删除和指定值相等的所有元素

  • unique:删除所有和前一个元素相同的元素

  • merge:合并两个链表,并清空被合并的链表

  • reverse:颠倒链表

  • splice:在指定位置前插入另一个链表中的一个或多个元素,并在另一个链表中删除被插入的元素。


关联容器

* set, multiset, map, multimap

    *  内部元素有序排列,新元素插入的位置取决于它的值,查找速度快

    * map关联数组:元素通过键来存储和读取

    * set大小可变的集合,支持通过键实现的快速读取

    * multimap支持同一个键多次出现的map类型

    * multiset支持同一个键多次出现的set类型

* 与顺序容器的本质区别

    * 关联容器是通过(key)存储和读取元素的

    * 而顺序容器则通过元素在容器中的位置顺序存储和访问元素。

    * 除了各容器都有的函数外,还支持以下成员函数:

    * 设m表容器,k表键值

  •  m.find(k) :如果容器中存在键为k的元素,则返回指向该元素的迭代器。如果不存在,则返回end()值。

  • m.lower_bound(k):返回一个迭代器,指向键不小于k的第一个元素

  • m.upper_bound(k):返回一个迭代器,指向键大于k的第一个元素

  • m.count(k) :返回m中k的出现次数

  • 插入元素用 insert(insert函数的返回值是一个pair对象,其first是被插入元素的迭代器,second代表是否成功插入了)

pair模板:

 pair模板类用来绑定两个对象为一个新的对象,该类型在<utility>头文件中定义。该模板类支持一下操作:

  • pair<T1,T2>p1:创建一个的pair对象,它的两个元素分别是T1和T2类型,采用值初始化;

  • pair<T1,T2>p1<v1,v2>:创建一个pair对象,它的两个元素分别是T1和T2类型,first成员初始化为v1,second成员初始化为v2;

  • make_pair(v1,v2):以v1、v2值创建一个新的pair对象,其元素类型分别是v1和v2的类型。

  • p.first  返回p中名为first的(公有)数据成员

  • p.second   返回p中名为second的(公有)数据成员

  • p1 < p2字典次序   如果p1.first<p2.first或者!(p2.first <p1.first)&& p1.second<p2.second,则返回true

  • p1 == p2     如果两个pair对象的first和second成员依次相等,则这两个对象相等。

map

template<class Key, class T,
                  class Pred = less<Key>,    class A = allocator<T> >
class map {

  ….

  typedef pair<const Key, T> value_type;

  …….

};

* map 中的元素关键字各不相同。元素按照关键字升序排列,缺省情况下用 less 定义“小于”

* 可以用下标的形式访问map中的元素。

/*
 统计一篇英文文章中单词出现的频率(为简单起见,假定依次从键盘输入该文章)
*/
int main()
{
  map<string, int> wordCount;      //map
  string word;                     //string
  while ( cin >> word )
  ++wordCount[word];           //单词频率统计
  map<string, int>::iterator it ;
  for ( it= wordCount.begin();  it != wordCount.end();  ++it)
  cout<<"Word: "<<(*it).first    
  <<" \tCount:"<<(*it).second<<endl;
  return 0;
}


容器适配器:stack

  可用vector、list、deque来实现

  • 缺省情况下用deque;

  • 用vector和deque比用list实现性能好

template<class T, class Cont=deque<T>>

    class stack{  ...  };

   stack是先进后出的数据结构,只能插入、删除、访问栈顶元素的操作:

  • push:插入元素

  • pop:弹出元素

  • top:返回栈顶元素的引用

 容器适配器:queue

    可以用list、deque实现,缺省情况下用deque;

template<class T, class Cont=deque<T>>

    class queue{   ...  };

   先进先出,也有push、pop、top函数,但push发生在队尾,另外俩在队头。

容器适配器:priority_queue

   和queue类似,可以用vector和deque实现,缺省情况下用vector实现。

    priority_queue通常用堆排序技术实现,保证最大的元素总在最前面。

    即执行pop操作,删除的是最大的元素;执行top操作时,返回的是最大元素的引用。默认的元素比较器是less<T>;

#include <queue>
#include <iostream>
using namespace std;
int main()  {
  priority_queue<double> priorities;
  priorities.push(3.2);
  priorities.push(9.8);
  priorities.push(5.4);
  while( !priorities.empty() ) {
  cout << priorities.top() << " ";    priorities.pop();
  }
     return 0;
}

//输出结果:9.8 5.4 3.2


排序和查找算法

/*sort*/
template<class RanIt>
  void sort( RanIt first,  RanIt last);

/*find*/
template<class InIt, class T>
InIt find(InIt first, InIt last, const T& val);

/*binary_search 折半查找,要求容器已经有序*/
template<class FwdIt, class T>
bool binary_search(FwdIt first, FwdIt last, const T& val);

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
  const int SIZE = 10;
  int a1[] = { 2,8,1,50,3,100,8,9,10,2 };
  vector<int> v(a1,a1+SIZE);
  ostream_iterator<int> output(cout," ");
  vector<int>::iterator location;
  location = find(v.begin(),v.end(),10);
  if( location != v.end())
      cout<< "1) " << location - v.begin() << endl ;
  sort(v.begin(),v.end());                           //sort()排序
  if( binary_search(v.begin(),v.end(),9))
      cout<< "2) " << "9 found" << endl ;
  else
      cout << "3) " << " 9 not found" << endl;      
  return 0;
}

参考老师课件嘻嘻嘻(*^▽^*)

猜你喜欢

转载自blog.csdn.net/qq_38735931/article/details/81812118
今日推荐