c++标准模板库STL 小结

目录

1、容器(container)

二、泛型算法(generic algorithm)

三、迭代器(iterator)

四、顺序容器之矢量类

 

vector- 变长数组

set-内部自动有序且不含重复元素

string-字符串处理

map-键值对

queue-队列

priority_queue-优先队列

stack-栈

pair


 

STL是一种泛型编程(generic programming)

  • STL提供了一组表示容器、迭代器、函数对象和算法的模板。
  • 面向对象编程关注的是编程的数据方面,而泛型编程关注的是算法
  • 他们之间的共同点是抽象和创建可重用代码,但是他们的理念截然不同。

1、容器(container)

  • 容器类是一个与数组类似的单元,但是他是管理序列的类,也是容纳一组对象对象集的类。
  • 通过容器类提供的成员函数,可以实现例如向序列中插入、删除、查找元素等操作;
  • 这些成员函数通过返回迭代器来指定元素在序列中的位置。

容器主要有以下分类:

二、泛型算法(generic algorithm)

  • 模板中的算法不依赖与具体的数据类型,而泛型算法更进一步不依赖于具体的容器。
  • 这也是STL最大的优点,就是他提供能在各种容器中通用的算法,例如:插入、排序、查找、删除等。
  • 一种算法可以适用于多种容器,故称为泛型算法;
  • 泛型算法之所以能够用于各种容器,是因为有迭代器。

三、迭代器(iterator)

  • STL设计的精髓在于把容器和算法分开,彼此独立设计,最后再用迭代器把他们合并在一起。

  • 迭代器是一种数据类型,他提供了一种方法,可以顺序访问一个容器中的每个元素,而又不暴露该对象的内部表示

  • 迭代器的用法和指针类似,只不过它相当于一个智能指针,它指向容器内部的数据,并可以通过解引用*来获取它指向的数据。

  • STL提供的所有容器都有这样的迭代器,用以存取他们所管理的元素序列。

例如:

容器的成员函数begin()返回指向容器中第一个元素的迭代器;end()返回指向容器中最后一个元素后继位置的迭代器。

下面通过STL中提供的一个泛型函数find()来说明迭代器与泛型算法的关系:

首先看下STL对于find函数的内部实现:

template <class input_iterator_tag,class T>
input_iterator_tag find(input_iterator_tag first,input_iterator_tag last,const T value)
{
    for(;first != last;first++)
    {
        if(value == *first)
            return first;
    }
    return last;
}

注意:

  • 源码中出现的input_iterator_tag是一个输入迭代器类,它的功能是从容器中读取元素。
  • 第一个参数和第二个参数给出了find函数要查找的范围,这个范围是一个左闭右开的区间:[first, last),last对应的元素不在查找范围内。
  • 这是一个普遍的约定,所有的泛型算法都遵守这个约定,在后面的程序中还会遇到的。

然后在应用程序中测试:

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int num[] = {1,2,3,4,5};
    int *result,value;
    cout << "please input the num you want to search:" ;
    cin>>value;
    result = find(num,num+5,value);    //注意这里模板参数被特化为int *
    if(result == num+5)
        cout<<"can't find the num you input\n\n";
    else
        cout<<"find it!,the index is:"<<result-num<<endl;
    return 0;
}

运行结果:

结合find()函数的源码可以知道,泛型算法不直接访问容器的的元素,与容器无关。元素的全部访问和遍历都通过迭代器实现,并不需要知道容器的类型。

四、顺序容器之矢量类

  • 矢量vector类是一个多功能、能够操作多种数据结构和算法的模板类和函数库。
  • 它和数组类似,通过下标运算符访问矢量中的元素,并且其元素具有连续的内存地址
  • vector类的一大优点是,他可以进行动态的内存管理。并且该类内部包含很多常用的函数、特有函数,用以实现堆栈、队列、列表等结构。

每种容器都有自己支持的迭代器类型,迭代器决定了可采用哪种算法。vector支持随机访问迭代器,能直接访问容器中的任意元素,功能比较强大。选择所需容器类实际上很大部分是选择所支持的迭代器。

下面通过一个简单的demo演示vector类的应用:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
    double values[] = {1,2,3,4,5,6,7};
    int i;
 
    //构造一个向量
    vector<double> dVector(values,values+7);
 
    cout<<"1.init value is:";
    for(i=0;i<dVector.size();i++)
        cout<<dVector[i]<<"\t";
    cout<<endl;
 
    dVector.assign(4,1.5);  //将1.5复制4份
    cout<<"2.after assign,the value is:";
    for(i=0;i<dVector.size();i++)
        cout<<dVector[i]<<"\t";
    cout<<endl;
 
    dVector.at(0) = 34.3;   //给向量中的第一个元素赋值
    cout<<"3.after the at,the value is::";
    for(i=0;i<dVector.size();i++)
        cout<<dVector[i]<<"\t";
    cout<<endl;
 
    //将首元素的迭代器赋值给itr
    vector<double>::iterator itr = dVector.begin();
    dVector.insert(itr+1,55);
    dVector.insert(itr+1,66);
    dVector.insert(dVector.begin()+1,0);    //这个用法和上面的用法一样
    cout<<"4.:after insert,the value is:";
    for(i=0;i<dVector.size();i++)
        cout<<dVector[i]<<"\t";
    cout<<endl;
    return 0;
}

运行结果:

更多vector类的成员函数可以访问: http://www.cplusplus.com/reference/vector/vector/?kw=vector

 

 

 

 


vector- 变长数组

添加头文件:

#include <vector>

定义vector:

vector<typename> name; //typename可以是任何基本类型,也可以是STL容器
vector<vector<typename> > name; //c++11之前会将>>视为移位操作,所以要加空格> >

定义vector数组:

vector<typename> Arrayname[arraySize]; //与vector<vector<typename> >不同的是一维已经固定长度为arraySize
  •  

访问:

  • 通过下标访问name[index]
  • 通过迭代器访问
    迭代器类似指针,定义为vector<typename>::iterator it = name.begin()
    得到 it 后通过 *it 来访问vector里的元素, *(it + i) 来访问第i个元素
    循环可以这样写:
for(vector<typename>::iterator it = name.begin(); it != name.end(); it++){}
  •  

常用函数:

  • push_back() 尾插,时间复杂度为O(1)O(1)
  • pop_back() 尾删,时间复杂度为O(1)O(1)
  • size() 长度,返回unsigned类型,时间复杂度为O(1)O(1)
  • clear() 清空,时间复杂度为O(n)O(n)
  • insert(it, x) 向迭代器it处插入元素x,时间复杂度为O(n)O(n)
  • erase()
    • 删除单个元素 erase(it)
    • 删除一个区间[first, last)的元素erase(first, last) //first与last都是迭代器
    • 时间复杂度均为O(n)O(n)

set-内部自动有序且不含重复元素

添加头文件:

#include <set>
  •  

定义set

set<typename> name;
  •  

访问
只能通过迭代器访问:

set<typename>::iterator it;
  •  

得到it之后按*it来访问set里的元素
由于除开vector和string之外的STL容器都不支持*(it + i)的访问方式,因此只能采用下列方式枚举:

for(set<typename>::iterator it = name.begin(); it != name.end(); it++){}
  •  

常用函数

  • insert() 时间复杂度O(logN)O(log⁡N),因为底层使用红黑树来实现
  • find(value) 返回对应值为value的迭代器,时间复杂度为O(logN)O(log⁡N)
  • erase()
    • 删除单个元素
      • name.erase(it) 时间复杂度为O(1)O(1)
      • name.erase(value) 时间复杂度为O(logN)O(log⁡N)
    • 删除一个区间[first, last)内的元素 name.erase(first, last), 时间复杂度为O(last−first)O(last−first)
  • size() 时间复杂度为O(1)O(1)
  • clear() 清空 O(N)O(N)

string-字符串处理

添加头文件

#include <string>
  •  

定义

string str;
string str = "abcd"; //定义的同时初始化
  •  
  •  

访问
读入输出只能用cin和cout
或者用c_str()将string类型转成字符数组,再用printf()输出

string str = "abcd";
printf("\n", str.c_str());
  •  
  • 通过下标访问
  • 通过迭代器访问
    与vector一样可以通过*(it + i)的方式访问

常用函数

  • += 拼接赋值
  • ==、!=、<、<=、>、>=比较大小,字典序
  • length()/size() 返回string长度,O(1)O(1)
  • insert() O(N)O(N)
    • insert(pos, string) 在pos位置插入string
    • insert(it, it2, it3) it为原字符串的欲插入位置,it2和it3为待插入字符串的首尾迭代器,[it2, it3)
  • erase()

    • erase(it) 删除单个元素
    • erase(first, last) 删除区间[first, last)的所有元素
    • erase(pos, length), 删除pos处开始的length长度的字符个数
  • clear() O(1)O(1)

  • substr(pos, len) 返回从pos号位开始,长度为len的子串,时间复杂度为O(len)O(len)
  • string::npos 是一个常数,用以find函数失配时的返回值,即等于-1也等于4294967295(unsigned_int类型最大值)
  • find()
    • find(str2) 找子串第一次出现的位置,若不是,返回string::npos
    • find(str2, pos), 从str的pos号位开始匹配str2
    • 时间复杂度为O(mn)O(mn),其中n和m分别是str和str2的长度
  • replace() O(str.length())O(str.length())
    • replace(pos, len, str2) 把str从pos号位开始,长度为len的子串替换为str2
    • replace(it1, it2, str2) 把str的迭代器[it1, it2)范围的子串替换为str2

map-键值对

添加头文件

#include <map>
  •  

定义

map<typename1, typename2> mp;
  •  

访问

  • 通过下标访问,例如mp[‘a’]
  • 通过迭代器访问
 - map<typename1, typename2>::iterator it;
 - for(map<typename1, typename2>::iterator it = mp.begin(); it != mp.end(); it++){
    //it->first; 访问键
    //it->second; 访问值
}
  •  

常用函数

  • find(key) 返回key的映射的迭代器, 时间复杂度为O(logN)O(log⁡N), 底层红黑树实现
  • erase()

    • erase(it) O(1)O(1)
    • erase(key) O(logN)O(log⁡N)
    • erase(first, last) 删除[first, last)区间元素,O(last−first)O(last−first)
  • size() O(1)O(1)

  • clear() O(N)O(N)

queue-队列

添加头文件

#include <queue>
  •  

定义

queue<typename> name;
  •  

访问

  • front() 访问队首
  • back() 访问队尾

常用函数

  • push() O(1)O(1)
  • front(),back() O(1)O(1)
  • pop() O(1)O(1) 队首出队
  • empty() 检测queue是否为空,返回true为空,O(1)O(1)
  • size() O(1)O(1)

priority_queue-优先队列

用堆来实现,每次插入元素根据元素的优先级向上调整到堆顶
添加头文件

#include <queue>
  •  

定义

priority_queue< typename > name;
  •  

访问
只能通过top()函数来访问队首元素(堆顶元素),也就是优先级最高的元素

常用函数

  • push() 往堆底插入元素,向上调整,所以时间复杂度为O(logN)O(log⁡N)
  • top() O(1)O(1)
  • pop() 令队首元素出队,将队尾元素复制到队首,并向下调整,删除队尾,所以时间复杂度为O(logN)O(log⁡N)
  • empty() 检测是否为空,O(1)O(1)
  • size() O(1)O(1)

优先级设置

  • 基本数据类型
priority_queue<int> q;
priority_queue<int, vector<int>, less<int> > q;//vector<int>填写的是来承载底层heap的容器,less<int>是对第一个参数的比较类,less<int>表示数字大的优先级越大
priority_queue<int, vector<int>, greater<int> > q;//数字小的优先级大
  • 结构体
struct student{
    //学生成绩
    string s_id;
    int s_grade;
    friend bool operator < (student s1, student s2){
        //重载< 重载>号会编译错误
        return s1.s_grade < s2.s_grade;//s_grade大的优先级高
        //若s_grade小的优先级高,则改为return s1.s_grade > s2.s_grade;
    }
}
priority_queue<student> q;

将重载<放到student结构体外

struct cmp{
    bool operator (const student &s1, const student &s2){
        //使用引用避免复制,提高效率
        return s1.s_grade > s2.s_grade;
    }
}
priority_queue<student, vector<student>, cmp> q;

stack-栈

添加头文件

#include <stack>
  •  

定义

stack<typename > name;
  •  

访问
使用top()来访问栈顶元素

常用函数

  • push() O(1)O(1)
  • top() O(1)O(1)
  • pop() O(1)O(1)
  • empty() O(1)O(1)
  • size() O(1)O(1)

pair

添加头文件

#include <utility>
  •  

定义

pair<typename1, typename2> p;
pair<string, int> p("jetlee", 18); //定义的同时初始化
//定义临时pair的两种方式
p = pair<string, int>("jetlee", 18);
p = make_pair("jetlee", 18);

访问
pair中只有两个元素,分别用first和second来访问

常用函数

  • 比较操作数:==、!=、<、<=、>、>=;比较规则是先比较first,first相同时再比较second

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值