容器的相关概念:
泛型编程是一种编程的理念,其提出的动机是发明一种语言机制,能够在编程中编写完全一般化的可重复使用的算法,不会因为数据类型的不同而有差异
美国的惠普实验室针对泛型编程开发了一系列软件工具,被称为标准模板库(STL),后续在C++中被广泛引入。STL中绝大多数的类型都使用了模板的编程技术,这相比传统的代码有更好的特性
STL中最核心的内容有两种:
(1)容器
容器指的是用来存储数据的集合,由于内部存储的数据使用模板实现,因此可以支持绝大多数树据类型。
容器类自动申请和释放资源,无需new和delete
容器分为两种
(1)顺序容器:
顺序容器是一种各元素之间有顺序关系的结果集合,每个元素在容器中都有固定的位置,但是可以用插入和删除等操作改变这个位置
顺序容器有:
(1)array 数组(C++11引入)
array是C++ 11中引入的容器类型,与传统数组相比,array更加安全和易于使用。
代码示例:
#include <iostream>
#include <array> // 引入头文件
using namespace std;
int main()
{
// 创建一个长度为5的int数组
array<int,5> arr = {2,4,6,8,10};
cout << arr[0] << endl; // 2
cout << arr[4] << endl; // 10
arr[1] = 666;
cout << arr.at(1) << endl; // 666
// 普通循环
for(int i=0;i<arr.size();i++)
{
cout << arr.at(i) << " ";
}
cout << endl;
// 给所有元素赋值
arr.fill(5);
// for-each循环
for(int i:arr)
{
cout << i << " ";
}
cout << endl;
return 0;
}
(2)vectory 向量
vector内部由数组实现,因此可以高效地进行元素的随机存取,但是插入和删除的效率较低,是最常用的一种顺序容器。
代码示例:
#include <iostream>
#include <vector> // 引入头文件
using namespace std;
int main()
{
// 创建一个长度为0的向量对象
vector<int> vec1;
cout << vec1.empty() << endl; // 1
// 创建一个长度为5的向量对象
vector<int> vec2(5);
vec2[0] = 123; // 修改元素
cout << vec2[0] << endl; // 123
cout << vec2.at(4) << endl; // 0
// 5个666
vector<int> vec3(5,666);
// 向后追加元素
vec3.push_back(888);
// 在第二个位置插入2
// 参数1:插入的位置
// 参数2:插入的元素
vec3.insert(vec3.begin()+1,2);
// 在倒数第二个位置插入222
vec3.insert(vec3.end()-1,222);
// 删除第一个元素
vec3.erase(vec3.begin());
// 删除最后一个元素
vec3.erase(vec3.end()-1);
vec3.pop_back(); // 删除最后一个元素
// 普通循环遍历
for(int i=0;i<vec3.size();i++)
{
cout << vec3.at(i) << " ";
}
cout << endl;
// 清空
vec3.clear();
// for-each遍历
for(int i:vec3)
{
cout << i << " ";
}
cout << endl;
return 0;
}
(3)list 列表
list内部由双向链表实现,因此元素的内存空间是不连续的,能高效地进行插入和删除操作,但是随机存取的效率较低,并且list只能通过迭代器指针来访问数据。
代码示例
#include <iostream>
#include <list> // 引入头文件
using namespace std;
int main()
{
// 创建一个四个hello元素的列表对象
list<string> lis1(4,"hello");
list<string> lis2;
// 判断是否为空
cout << lis2.empty() << endl;
// 向后追加元素
lis1.push_back("bye");
// 向前追加元素
lis1.push_front("start");
// 取出头部元素
cout << lis1.front() << endl;
// 取出尾部元素
cout << lis1.back() << endl;
// 删除头部元素
lis1.pop_front();
// 删除尾部元素
lis1.pop_back();
// 在第二个位置插入元素"2B"
lis1.insert(++lis1.begin(),"2B");
// 在倒数第二个位置插入元素"2Y"
lis1.insert(--lis1.end(),"2Y");
// 保存迭代器指针
list<string>::iterator iter = lis1.begin();
// 修改第一个元素
*iter = "One";
// 取出元素
cout << *iter << endl;
// 移动迭代器指针
// 参数1:要移动的迭代器指针对象
// 参数2:移动的距离
advance(iter,3);
// 在第四个元素的位置插入"4544"
lis1.insert(iter,"4544");
// 删除倒数第一个元素
lis1.erase(--lis1.end());
// 清空
// lis1.clear();
// 排序
lis1.sort();
// 不支持普通的for循环遍历,但是支持for-each遍历
for(string s:lis1)
cout << s << " ";
cout << endl;
return 0;
}
(4)deque 队列
即支持list的指针操作,又支持vector的下标操作,是一种性能均衡的容器
(5)string 字符串
(2)关联容器:
关联容器的各元素直接没有严格的物理上顺序关系,但是内部有排序,因此可以使用迭代器遍历
关联容器内部的元素数据以键值对(key-value pair)的形式存在。
键必须唯一,通常使用字符串类型;值可以重复,可以是任何类型。
map与multimap的区别在于,前者是单重键值对映射(一一映射),后者允许一个键对应多个值,map更为常用。
map代码示例:
#include <iostream>
#include <map> // 引入头文件
using namespace std;
int main()
{
// 创建一个内容为空的map对象
map<string,int> map1;
// 添加元素
map1["height"] = 180;
map1.insert(pair<string,int>("country",86));
map1["salary"] = 10000;
map1["age"] = 40;
map1["weight"] = 71;
// 已经存在这个键值对,因此再次赋值就是修改键对应的值
map1["weight"] = 70;
// 删除元素
if(map1.erase("salary"))
{
cout << "删除成功,还剩下" << map1.size() << "个键值对" << endl;
}else
{
cout << "删除失败!" << endl;
}
// 迭代器指针
// 如果有对应的键,则指向键值对
// 如果没有对应的键,则执指向“最后一个元素”的后面
map<string,int>::iterator iter = map1.find("salary");
if(iter != map1.end())
{
// 取出元素
int value = iter->second;
cout << value << endl;
}else
{
cout << "没有对应的值!" << endl;
}
// 清空
map1.clear();
cout << map1.empty() << endl;
return 0;
}
(2)迭代器
迭代器是一种配合容器进行高效便利的工具,是一种特殊的指针
容器的遍历通常是迭代器进行,因为迭代器对容器便利的兼容性最好,且遍历效率最高。迭代器死一种特殊的指针,如果要使用迭代器进行读写操作,可以使用iterator类型的迭代器;如果要使用迭代器进行只读操作,可以使用const_iterator类型的迭代器,因为只读迭代器的效率更高
代码示例:
#include <iostream>
#include <array>
#include <vector>
#include <list>
#include <deque>
#include <map>
using namespace std;
int main()
{
string str = "ABC678%^";
// string的只读迭代器
for(string::const_iterator iter = str.begin();iter != str.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
array<double,20> arr;
arr.fill(3.14);
// array的读写迭代器
for(array<double,20>::iterator iter = arr.begin();
iter!=arr.end();iter++)
{
cout << ++(*iter) << " ";
}
cout << endl;
vector<int> vec1(4,4);
// vector的只读迭代器
vector<int>::const_iterator iter_vec = vec1.begin();
while(iter_vec != vec1.end())
{
cout << *iter_vec << " ";
iter_vec++;
}
cout << endl;
list<string> lis1;
lis1.push_back("fhdjks");
lis1.push_back("fhfggks");
lis1.push_back("dsdsghs");
lis1.push_back("fh***");
// list的读写迭代器
list<string>::iterator iter_lis = lis1.begin();
while(iter_lis != lis1.end())
{
cout << (*iter_lis).append("~") << " ";
iter_lis++;
}
cout << endl;
deque<int> deq(5,5);
// deque的读写迭代器,也可以只读
for(deque<int>::iterator iter = deq.begin();
iter!=deq.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
map<string,string> map1;
map1["城市"] = "济南";
map1["name"] = "Tom";
map1["age"] = "7";
map1["friend"] = "Jerry";
// map的只读迭代器
for(map<string,string>::const_iterator iter = map1.begin();
iter != map1.end();iter++)
{
cout << iter->first << "-"; // 键
cout << iter->second << endl; // 值
}
return 0;
}