C++STL总结

(一)STL概述

1.什么是STL?
标准模板类(Standard Template Library)
2.STL主要由几部分组成?
算法、容器、迭代器
3.STL主要用了什么技术实现?
模板技术
4.如何宣称与使用名空间,如何使用stl的名空间?

namespace MySpace {
void func(){
cout<<"myspace"<<endl;
}
MySpace::func();

5.算法、迭代器与容器之间的关系以及迭代器的作用:
容器:管理某一类对象的集合;
算法:作用于容器,它提供了执行各种操作的方式,包括对容器的内容执行初始化、排序、搜索和转换等操作;
迭代器:用于遍历对象集合的元素。
迭代器的作用:
(1)每个容器都有相应的迭代器,容器通过迭代器共享某一具体的算法;
(2)但某一具体算法不依赖于某一具体容器,迭代器起到了中间媒介的作用,把容器和算法连接起来;
(3)迭代器思维是编制通过泛型算法发展的必然结果,算法通过迭代器访问容器中的元素。
6. 返回布尔值的函数对象称为谓词,默认是“<”操作符。

(二)模板

1.函数模版、类模版和模版特化、实例化
模板:将数据类型参数化的工具,它提供了一种将代码与数据类脱离的机制,即:代码不受具体的数据类型的影响。
模板分为函数模板和类模板两种。
模板被调用时,编译器根据实际参数的类型确定模板参数T的类型,并自动生成一个对应的模板函数或模板类。
(1)函数模板:不说明某些参数的数据类型的函数。

(2)类模板:不说明某些成员变量的数据类型的类。

(3)模板特化(类中直接指定数据类型)——上面

(4)实例化:(在用的时候指明类型)——下面

2.模版参数怎样传递?
编译器检查实参的类型,产生该类型对应的模板类或模板函数。
3.什么情况不需要传递模版参数?
特化
4.模版特化如何实现的?
在类中指定数据类型
5.优先级队列、set和map类如何指定排序的算法类型?
优先队列默认按照优先级降序排列,map和set默认按照键值升序排列。
(1)指定谓词
(2)重载"<"符号
6.STL与模版关系:
STL的实现大量运用了模板技术
STL包含各种泛型算法(algorithms)、泛型指针(iterators)、泛型容器(containers)以及函数对象(function objects),是以迭代器和容器为基础的一种泛型算法库,模板是泛型的实现,故而STL的实现大量运用了模板技术
7.STL的traits是怎样实现的?
(1)traits技术的定义:提取不同类的共性,traits依靠显式模板特殊化来把代码中因类型不同而发生变化的片段拖出来,用统一的接口包装
(2)① 定义基本模板类 ② 模板特化 ③统一模板调用类编制

//代码实现:
#include <iostream>
using namespace std;

//定义基本模板类 
class CIntArray
{
private:
	int a[10];

public:
    CIntArray()
    {
	    for(int i=0;i<10;i++)
	    {
	    	a[i]=i+1;
	    }
    }
   int GetSum(int times)
   {
	   int sum=0;
	   for (int i=0;i<10;i++)
	   {
		   sum+=a[i];
	   }
	   return sum*times;
    }
};

class CFloatArray
{
	float f[10];
public: CFloatArray()
    {
	    for(int i=1;i<=10;i++)
	    {
	    	f[i-1]=1.0f/i;
	    }
    }
   int GetSum(float times)
   {
	   float sum=0.0f;
	   for (int i=0;i<10;i++)
	   {
		   sum+=f[i];
	   }
	   return sum*times;
    }
};

//模板特化 
template<class T>
class NumTraits{};

template<>
class NumTraits<CIntArray>
{
public:
    typedef int resulttype;
    typedef int inputpara;
};
template<>
class NumTraits<CFloatArray>
{
public:
    typedef float resulttype;
    typedef float inputpara;
};
//统一模板调用类编制 
template<class T>
class CArry
{
public:
    typedef typename NumTraits<T>::resulttype result;
    typedef typename NumTraits<T>::inputpara input;
    result Getsum(T&obj,input times)
    {
        return obj.GetSum(times);
    }
};


int main()
{
	CIntArray intary;
	CFloatArray fltary;
	CArry<CIntArray>obj1;
	CArry<CFloatArray>obj2;
	cout<<obj1.Getsum(intary,2)<<endl;
	cout<<obj2.Getsum(fltary,3.2f)<<endl;
	return 0;
}

(三)迭代器

1.什么是迭代器?迭代器是指针吗?
迭代器:用于遍历对象集合的元素。
迭代器是STL的核心技术,是通用算法的技术基础。
(1) 迭代器是仿指针的类模板。像是指针操作符,->,*,++ --封装了指针,是一个“可遍历STL( 标准模板类、Standard Template Library)容器内全部或部分元素”的对象, 本质是封装了原生指针,是指针概念的一种提升,提供了比指针更高级的行为:根据不同类型的数据结构来实现不同的++,–等操作;
(2)通过迭代器,容器和算法可以有机的粘合在一起,我们基本上不需要考虑底层的实现就可以完成一些通用算法。使用迭代器算法后需要注意失效问题。
(3)指针能指向函数,迭代器只能指向容器。
2.迭代器分多少种?
输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器
3.有哪些迭代器适配器?
插入迭代器、逆向迭代器
① front_insert_iterator(Cont &) : ->函数模板:front_inseter(Cont &) ,基本容器类必须有push_front()方法,故list, deque 可以【vector不可以,无push_front()】
② back_insert_iterator(Cont &):->函数模板:back_inserter(Cont &),基本容器类必须有push_back()方法,故vector, list, deque都可以。
③ insert_iterator(Cont &, Cont::iterator):->函数模板:inserter(Cont &, Cont::iterator),基本序列式容器都适合,只要有insert方法
④ reverse_iteratorCont::iterator(Cont::iterator)
4.迭代器的作用?
迭代器:用于遍历对象集合的元素
(1)每个容器都有相应的迭代器,容器通过迭代器共享某一具体的算法;
(2)但某一具体算法不依赖于某一具体容器,迭代器起到了中间媒介的作用,把容器和算法连接起来;
(3)迭代器思维是编制通过泛型算法发展的必然结果,算法通过迭代器访问容器中的元素。
5.迭代器怎样访问元素: , ->*
6.stl标准模板库编程步骤
(1)形成容器元素
(2) 取出所需要的迭代指针
(3) 调用通用算法
7.熟练使用迭代器的advance、distance,为何要使用这些函数?
因为只有随机访问迭代器才可以将一个整数移动到指定位置,也只有随机访问迭代器可以相减获得两迭代器之间的元素个数。而对于其他迭代器,是不能进行上述操作的。
故用advance, distance 对底层操作封装,向用户提供语义上与上述作用相同的接口来实现相同的目的,从而对于list等容器也可以进行类似前加和相减的操作。

(四)输入输出流

1. 都有哪些流?
(1) 基本输入输出流:istream ostream iostream
(2) 文件输入输出流:ifstream ofstream fstream
(3) 字符串输入输出流 : ():istringstream ostringstream stringstream
2. stringstream和其他流有何区别?
答: 字符串输入输出流类直接对内存而不是对文件和标准输出输入进行操作。
3. 文件流如何关联文件?操作流文件如何制定文件的打开方式?
(1) 打开:ifstream in(“a\b.txt”,ios::trunc);
//ifstream in; in.open(“a\b.txt”,ios::trunc);
(2) 关闭:in.close();
打开方式:
ios::in 以读取方式打开文件
ios::out 以写入方式打开文件
ios::app 每次写入数据时,先将文件指针移到文件尾,以追加数据到尾部
ios::ate 仅初始时将文件指针移到文件尾,仍可在任意位置写入数据
ios::trunc 写入数据前,先删除文件原有内容(清空文件),当文件不存在时会创建文件
ios::binary 以二进制方式打开文件,不作任何字符转换
4.流的状态如何检测?
good() :true——一切正常,没有发生任何错误
eof() :true——已到达文件的末尾
fail() :true——I/O操作失败,主要原因是非法数据,但流还可继续使用
bad() :true——发生致命错误(硬件错误),流不能继续使用
5.文本与2进制文件的读写操作:
read()
write()
6.如何控制流的游标位置?
ios::beg:流的开始位置
ios::cur:流的当前位置
ios::end:流的结束位置
字符串
get函数及getline函数都是读一行记录,那么它们有什么区别呢?
细微而重要的区别在于:当遇到输入流中的界定符(delim,即结束字符)时get()停止执行,但是并不从输入流中提取界定符,直接在字符串缓冲区尾部加结束标志’\0’;函数getline()则相反,它将从输入流中提取界定符,但仍然不会把它存储到结果缓冲区中。
加粗样式

(五)函数对象

1. 什么是函数对象?它通常用在什么地方?
函数对象就是重载了operator()的类对象,又称仿函数。
通常情况下,函数对象被作为实参传递给泛型算法,来完全解决类型依赖性问题。
和“引用”一样,“函数对象”很少独立使用。
2. 函数对象带来的好处?
(1) 保存成员变量的状态:和函数指针相比,函数对象可以保存函数对象内部成员变量的状态,而函数指针对应的函数体内,除非将变量声明为static 或全局,否则是不可以保存变量状态的
(2) 函数对象可以附带数据:将数据通过构造函数的参数传给内部变量,而函数指针不可以。
(3) 直接以适配器的方式进行过扩展:函数对象可以直接以适配器方式进行拓展,而普通函数要想拓展必须运用普通函数适配器ptr_fun封装成一元或二元函数对象。
3.函数对象与函数指针相比较有三个优点:
(1)内联函数:函数指针是间接引用,不能作为内联函数,但函数对象可以,这样速度更快;
(2)数据域:类的数据域、函数对象可以拥有任意数量的额外数据,用这些数据来缓冲当前数据和结果,提高运行质量;
(3)类型检查:编译时函数对象作类型检查。
容器

  • hash_map和map的区别:
    (1)构造函数:hash_map需要hash函数、等于函数,map只需要比较函数(小于函数);
    (2)存储结构:hash_map采用hash表存储,map一般采用红黑树实现,因此其memory数据结构不同;
    2.容器分为哪2大类,都有哪些容器;有哪些容器适配器?其特性是什么?
    (1) 序列式容器:元素是按它们在容器中的位置来顺序保存和访问的,初始化时不一定会排好序
    (2) 关联容器:元素按关键字来保存和访问,更注重快速和高效的检索数据的能力,初始化后一定排好序

    (1) 序列式容器:vector, list, deque
    (2) 关联式容器:set, multiset, map, multimap
    (3) 容器适配器:stack, queue, priority_queue

  • stack(default=deque):push() pop() top(), 基本容器类必须有 push_back()、pop_back(),back()方法,故deque,list, vector可以。

  • queue(default=deque):push() pop() front() back() ,基本容器类必须有push_back()、pop_front() front() back() 方法, 故deque , list可以。 【vector不可, 因为其无pop_front()】

  • priority_queue(default=vector):push() pop() top(), 基本容器必须有随机访问迭代器,支持front() push_back() pop_back(), 故deque,vector可以。 【list不可,因为其迭代器是双向而非随机】
    3. 关联容器有什么?简单介绍他们的组成?各有什么特色?
    答:map、multimap、set、multiset
    关联式容器提供根据元素特点排序的功能;并且以键值的方式来保存数据,可以通过关键字直接访问数据。

  • set:元素不能重复;默认按照升序排列;内部通过链表的方式来组织

  • multiset:不要求集合元素唯一

  • map:提供一种“键-值”关系的一对一的数据存储能力;键值不可重复;默认升序;按链表方式存取。

  • multimap:不要求键值唯一

4.容器适配器有哪三种?特点是什么?
容器适配器是使事物的行为类似于另一事物的行为的一种机制。
(1)stack(栈)
它关联的基本容器可以是任意一种顺序容器,因为这些容器类型结构都可以提供栈的操作有求,它们都提供了push_back 、pop_back 和back 操作;
默认容器:deque
(2)queue(队列)
适配器要求其关联的基础容器必须提供pop_front 操作,因此其不能建立在vector 容器上;
默认容器:deque
(2)priority-queue(优先级队列)
元素插入是自动按优先级顺序插入,使最高优先级元素首先从优先级队列中取出;
默认容器:vector
要求提供随机访问功能,因此不能建立在list 容器上。
5. 都有哪些容器、容器适配器;都需要怎样遍历?
(1) vector : [], at(), iterator 3种方式,无push_front(),pop_front(),有front(),back(),pop_back(),push_back()
(2) deque : [],at(),iterator,有front(),back(),push_front(),pop_front(),push_back(),pop_back()
(3) list : (std::sort无法直接被使用,因为list无法随机访问,但提供了自己的std::list::sort函数)只能用iterator遍历,有front(),back(),push_front(),pop_front(), push_back(),pop_back()
(4) queue< T, Cont = deque>() : push() pop() 独有:front() back(), 无迭代器,只能pop遍历

//queue的遍历
void fun(queue<int>, deque<int> > obj) {
    while(!obj.empty() ){
        cout<<obj.front()<<"\t";
        obj.pop();
    }
}

(5) stack<T, Cont=deque>():push() pop() 独有:top(),无迭代器,只能pop遍历

//stack的遍历
void fun(stack<int, vector<int> > obj){
    while(!obj.empty()){
        cout<<obj.top()<<"\t";
        obj.pop();
    }
}

(6) priority_queue< T, cont=vector, deault=less >() : push() pop() 独有top(),只能pop遍历

//priority_queue的遍历
void fun(priority_queue<int, vetor<int>, greater<int> > obj){
    while(!obj.empty()){
        cout<<obj.top()<<"\t";
        obj.pop();
    }
}

int main(){
    priority_queue<int, vector<int>, greater<int> > obj;
    for(int i = 0 ; i < 4; i++){
        obj.push(i + 1);
    }
    fun(obj);
}

(7)set, map
6. 适配器是不独立的,他依附于一个序列容器上,他没有自己的构造函数和析构函数,而是借用其他类实现对应函数。
7. map如果数据如何初始化,如何访问?

答:
(1) set(集合)
① set : pair<iterator, bool>insert(&key) , iterator insert(iterator , &key) 若插入成功,返回指向插入值的迭代器,若失败,返回和插入值相同的那个迭代器和flase
② multiset :iterator insert(&key), iterator insert(iterator, &key) 返回指向插入值的迭代器,如果和某值相等,则返回最后一个和他相等的迭代器
(2) map (映射)
① map : pair<iterator,bool>insert(&value_type), iterator insert(iterator, &value_type)
② multimap : iterator insert(&value_type), iterator insert(iterator,&value_type)
(3) map[]不命中返回默认值,string是空串 int 是0


```cpp
#include <iostream>
#include <map>
#include <string>
using namespace std;
void display(map<int,string> & m)
{
    map<int ,string>::iterator te=m.begin();
    while(te!=m.end())
    {
        cout<<(*te).first<<" "<<(*te).second<<endl;
        te++;
    }
}
int main() {
map<int,string> mymap;
pair<int,string> s1(1,"zhangsan");
pair<int,string> s2(3,"Lisi");
pair<int,string> s3(6,"wangwu");
pair<int,string> s4(5,"zhaoliu");
pair<int,string> s5(1,"zhangsan");
mymap.insert(s1);
mymap.insert(s2);
mymap.insert(s3);
mymap.insert(s4);
mymap.insert(s5);
cout<<"通过insert创建的map"<<endl;
display(mymap);
cout<<"复制构造函数创建map"<<endl;
map<int, string> mymap2(mymap);
display(mymap2);
return 0;
}

#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, string> m;
m["1-1"] = "yuandan";
m["5-1"] = "laodongjie";
m["7-1"] = "party";
m["10-1"] = "country";
 
    string s = m["1-1"];
cout << s << endl;
    string s1 = m["6-1"];
if (s1.size() > 1)
cout << s1 << endl;
else
cout << "failed" << endl;
return 0;
}

``

(六)算法

1. count_if find_if 加不加 if有何区别?
(1) 不加if,根据值的内容与容器内元素是否相等进行判断
(2) 加if,根据容器内元素是否满足谓词进行判断,可以自定义一元谓词
(3) find(fist_iter, last_iter, value) find_if(first_iter, last_iter, pred)
(4) count(fist_iter,last_iter,value) count_if(fist_iter,last_iter,pred)
2. copy(first_iter, last_iter, first_iter_2)
3. for_each(first_iter, last_iter, func)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值