C++ STL & 标准库

STL

         STL(标准模板库)是一套 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。

         C++ STL的核心包括三个组件:

容器(Containers) 用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。
算法(Algorithms) 算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。
迭代器(iterators) 迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。

         三个组件都带有丰富的预定义函数,帮助我们通过简单的方式处理复杂的任务。

容器(vector )

定义

         Vector是最常用的容器之一,是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组,因为其大小是根据实时更新而变化的。

           vector的定义如下:

Vector<类型> 标识符
Vector<类型> 标识符(最大容量)
Vector<类型> 标识符(最大容量,初始所有值)
Vector<类型> v(i,i+2);     //得到i索引值为3以后的值
Vector< vector< int> >v;   //二维向量,这里最外的<>要有空格。否则在比较旧的编译器下无法通过

         例如:

vector<int> v;           // 储存int型的值 
vector<double> v;        // 储存double型的值 
vector<string> v;        // 储存string型的值 
vector<struct> v;        // 储存结构体或者类的值的值 

/* 可以定义vector数组 */
vector<int> a[n];        // 储存int型的值 
vector<double> a[n];     // 储存double型的值 

特性 

         容器特性:

  • 顺序序列:顺序容器中的元素按照严格的线性顺序排序。可以通过元素在序列中的位置访问对应的元素。
  • 动态数组:支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作。提供了在序列末尾相对快速地添加/删除元素的操作。
  • 内存分配感知(Allocator-aware):容器使用一个内存分配器对象来动态地处理它的存储需求。

成员函数       

构造函数
vector();                       //创建一个空vector
vector(int nSize);              //创建一个vector,元素个数为nSize
vector(int nSize,const t& t);   //创建一个vector,元素个数为nSize,且值均为t
vector(const vector&);          //复制构造函数
vector(begin,end);              //复制[begin,end)区间内另一个数组的元素到vector中
增加函数
/* 向量尾部增加一个元素X */
void push_back(const T& x);    
/* 向量中迭代器指向元素前增加一个元素x */              
iterator insert(iterator it,const T& x); 
/* 向量中迭代器指向元素前增加n个相同的元素x */    
iterator insert(iterator it,int n,const T& x); 
/* 向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据 */
iterator insert(iterator it,const_iterator first,const_iterator last);
删除函数
iterator erase(iterator it);                   //删除向量中迭代器指向元素
iterator erase(iterator first,iterator last);  //删除向量中[first,last)中元素
void pop_back();                               //删除向量中最后一个元素
void clear();                                  //清空向量中所有元素

遍历函数
reference at(int pos);       //返回pos位置元素的引用
reference front();           //返回首元素的引用
reference back();            //返回尾元素的引用
iterator begin();            //返回向量头指针,指向第一个元素
iterator end();              //返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin();   //反向迭代器,指向最后一个元素
reverse_iterator rend();     //反向迭代器,指向第一个元素之前的位置
判断函数
bool empty() const;          //判断向量是否为空,若为空,则向量中无元素
大小函数
int size() const;             //返回向量中元素的个数
int capacity() const;         //返回当前向量所能容纳的最大元素值
int max_size() const;         //返回最大可允许的vector元素数量值

/* 如果n小于当前容器的大小,则将内容减少到其前n个元素,并删除超出范围的元素(并销毁它们)*/
void resize(size_type n);    

/**
  *如果n大于当前容器的大小,则通过在末尾插入所需数量的元素来扩展内容,以达到n的大小。
  *如果指定了val,则将新元素初始化为val的副本,否则将对它们进行值初始化。
  *如果n也大于当前容器容量,将自动重新分配已分配的存储空间 
  */
void resize(size_type n, const value_type& val);

/**
  *表示预分配n个元素的存储空间,但不是真正的创建对象,
  *需要通过insert()或push_back()等操作创建对象。
  *调用reserve(n)后,若容器的capacity<n,则重新分配内存空间,从而使得capacity等于n。
  *若capacity>=n,capacity无变化。
  */
void reserve(size_type n);
resize() 和 reverse()区别

         容器调用resize()函数后,所有的空间都已经初始化了,所以可以直接访问。而reserve()函数预分配出的空间没有被初始化,所以不可访问。区别:

  • reserve()只修改capacity大小,不修改size大小,
  • resize()既修改capacity大小,也修改size大小。

          下面用实例进行说明:

#include <iostream>
#include <vector>

using namespace std;

int main(void)
{
    vector<int> v;
    cout<<"v.size() == " << v.size() << " v.capacity() = " << v.capacity() << endl;
	
    v.reserve(10);
	cout<<v[5]<< endl;
    cout<<"v.size() == " << v.size() << " v.capacity() = " << v.capacity() << endl;
	
    v.resize(10);
    v.push_back(0);
    cout<<"v.size() == " << v.size() << " v.capacity() = " << v.capacity() << endl;

    return 0;
}

         执行结果如下:

v.size() == 0 v.capacity() = 0
1735357008
v.size() == 0 v.capacity() = 10
v.size() == 11 v.capacity() = 20

注: 对于:v.reserve(10) 后接着直接使用 [ ] 访问越界报错(内存是野的),这里直接用[ ]访问,vector 退化为数组,不会进行越界的判断。此时推荐使用 at(),会先进行越界检查,如下所示:

cout<<v.at(5)<< endl;

v.size() == 0 v.capacity() = 0
terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check: __n (which is 5) >= this->size() (which is 0)

相关引申:

         针对 capacity 这个属性,STL 中的其他容器,如 list、 map、set、deque,由于这些容器的内存是散列分布的,因此不会发生类似 realloc() 的调用情况,因此可以认为 capacity 属性针对这些容器是没有意义的,因此设计时这些容器没有该属性。在 STL 中,拥有 capacity 属性的容器只有 vector 和 string。

capacity() 和 size() 的区别
  • size() :当前 vector 容器真实占用的大小,也就是容器当前存储的个数。
  • capacity() :容器可存储的最大总数,即预分配的内存空间。

         这两个属性分别对应两个方法:resize() 和 reserve()。       

其他
/* 交换两个同类型向量的数据 */
void swap(vector&);
/* 设置向量中前n个元素的值为x */
void assign(int n,const T& x);//
/* 向量中[first,last)中元素设置成当前向量元素 */
void assign(const_iterator first,const_iterator last);

实例

pop_back() & push_back()

         在容器最后移除和插入数据:

#include<iostream>
#include<vector>
#include<string.h>

using namespace std;

int main()
{
	vector<int> obj;               // 创建一个向量存储容器 int
	for(int i=0;i<10;i++)          // 依次在数组最后添加数据
	{
		obj.push_back(i);
		cout<<obj[i]<<"\t";
	}
	
	for(int j=0;j<5;j++)           // 依次去掉数组最后一个数据 
	{
		obj.pop_back();
	}
	
	cout<<"\n"<<endl;
	
	for(int k=0;k<obj.size();k++)  // size()返回容器中实际数据个数 
	{
		cout<<obj[k]<<"\t";
	}
	
	return 0;
}

         执行结果如下:

0       1       2       3       4       5       6       7       8       9

0       1       2       3       4

clear()

         清除容器中所有数据:

#include<string.h>
#include<vector>
#include<iostream>

using namespace std;

int main()
{
	vector<int> obj;
	for(int i=0;i<10;i++)
	{
		obj.push_back(i);
		cout<<obj[i]<<"\t";
	}
	
	obj.clear();
	cout<<endl;
	for(int i=0;i<obj.size();i++)
	{
		cout<<obj[i]<<"\t";
	}
	cout<<endl<<"size = "<<obj.size()<<", capacity = "<<obj.capacity();
	
	return 0;
}

         执行结果如下:

0       1       2       3       4       5       6       7       8       9

size = 0, capacity = 16

排序

         sort() 函数需要包含头文件: #include <algorithm>

#include<string.h>
#include<vector>
#include<iostream>
#include<algorithm>    // 'sort()' and 'reverse()' was declared in this Header file

using namespace std;

int main()
{
	vector<int> obj;
	
	obj.push_back(1);
	obj.push_back(2);
	obj.push_back(3);
	
	cout<<"由小到大:"<<endl;
	sort(obj.begin(),obj.end());
	for(int i=0;i<obj.size();i++)
	{
		cout<<obj[i]<<"\t";
	}
	
	cout<< endl <<"由大到小:"<<endl;
	reverse(obj.begin(),obj.end());
	for(int i=0;i<obj.size();i++)
	{
		cout<<obj[i]<<"\t";
	}
	
    return 0;	
}

         执行结果如下:

由小到大:
1       2       3

由大到小:
3       2       1

         如果想 sort 来降序,可重写 sort

/* 升序排列,如果改为return a>b,则为降序  */
bool compare(int a,int b) 
{ 
    return a< b; 
} 

/* 示例 */
int a[20]={2,4,1,23,5,76,0,43,24,65},i; 
for(i=0;i<20;i++) 
{
    cout<< a[i]<< endl; 
}
sort(a,a+20,compare);

         如下所示:

#include<string.h>
#include<vector>
#include<iostream>
#include<algorithm>    // 'sort' and 'reverse' was declared in this Header file

using namespace std;

bool compare(int a,int b) 
{ 
    return a > b; 
} 

int main()
{
	vector<int> obj;
	
	obj.push_back(1);
	obj.push_back(2);
	obj.push_back(3);
	
	cout<<"由小到大:"<<endl;
	sort(obj.begin(),obj.end());
	for(int i=0;i<obj.size();i++)
	{
		cout<<obj[i]<<"\t";
	}
	
	cout<< endl <<"由大到小:"<<endl;
	sort(obj.begin(),obj.end(),compare);  //sort 来降序
	for(int i=0;i<obj.size();i++)
	{
		cout<<obj[i]<<"\t";
	}
	
    return 0;	
}
直接数组访问&迭代器访问
#include<iostream>
#include<string.h>
#include<vector>
#include<algorithm>

using namespace std;

int main()
{
	vector<int> obj;
	for(int i=0;i<10;i++)
	{
		obj.push_back(i);
	}

	// 方法一:直接数组访问
	cout<<"直接利用数组:"<<"\t";
	for(int i=0;i<10;i++)
	{
		cout<<obj[i]<<"\t";
	}
	
	// 方法二:迭代器访问
	cout<<endl;
	cout<<"利用迭代器:"<<"\t";
	vector<int>::iterator it;
	for(it=obj.begin();it!=obj.end();it++)
	{
		cout<<*it<<"\t";
	}
	
	return 0;
}

         执行结果如下:

直接利用函数:  0       1       2       3       4       5       6       7       8       9
利用迭代器:     0       1       2       3       4       5       6       7       8       9

二维数组两种定义方法

         假设定义一个二维数组obj[5][6],两种定义方法的结果一样:

方法一
#include<iostream>
#include<vector>
#include<string.h>
#include<algorithm>

using namespace std;

int main()
{
	int N=5,M=6;                   // 定义二维动态数组大小5行为5行6列,值默认全为0
	vector< vector<int> > obj(N);  // 开辟行
	for(int i=0;i<obj.size();i++)
	{
		obj[i].resize(M);          // 开辟行
	}
	
	for(int i=0;i<obj.size();i++)  // 赋值,并输出二维动态数组 
	{
		for(int j=0;j<obj[i].size();j++)
		{
			obj[i][j]=i+j;
			cout<<obj[i][j]<<"\t"; 
		}
		cout<<endl;
	}
	
	return 0;
}
方法二
#include<iostream>
#include<vector>
#include<string.h>
#include<algorithm>

using namespace std;

int main()
{
	int N=5,M=6;                   // 定义二维动态数组大小5行为5行6列,值默认全为0
	
	/* 创建一个vector,元素个数为N,且值均为一个元素个数为M的vector<int>(M) */ 
	vector< vector<int> > obj(N,vector<int>(M)); 
	
	for(int i=0;i<obj.size();i++)  // 赋值,并输出二维动态数组 
	{
		for(int j=0;j<obj[i].size();j++)
		{
			obj[i][j]=i+j;
			cout<<obj[i][j]<<"\t"; 			
		}
		cout<<endl;
	}

	return 0;
}

         输出结果为:

0       1       2       3       4       5
1       2       3       4       5       6
2       3       4       5       6       7
3       4       5       6       7       8
4       5       6       7       8       9

标准库

         C++ 标准库可以分为两部分:

  • 标准函数库: 由通用的、独立的、不属于任何类的函数组成的。它继承自 C 语言。
  • 面向对象类库: 这个库是类及其相关函数的集合。

         C++ 标准库包含了所有的 C 标准库,为了支持类型安全,做了一定的添加和修改。

标准函数库

         标准函数库分为以下几类:

  • 输入/输出 I/O
  • 字符串和字符处理
  • 数学
  • 时间、日期和本地化
  • 动态分配
  • 其他
  • 宽字符函数

面向对象类库

         面向对象类库定义了大量支持一些常见操作的类,比如输入/输出 I/O、字符串处理、数值处理。面向对象类库包含以下内容:

  • 标准的 C++ I/O 类
  • String 类
  • 数值类
  • STL 容器类
  • STL 算法
  • STL 函数对象
  • STL 迭代器
  • STL 分配器
  • 本地化库
  • 异常处理类
  • 杂项支持库

猜你喜欢

转载自blog.csdn.net/weixin_60461563/article/details/132859978
今日推荐