1、vector容器
1.1vector性质
a)该容器的数据结构和数组相似,被称为单端数组。
b)在存储数据时不是在原有空间上往后拓展,而是找到一个新的空间,将原数据深拷贝到新空间,释放原空间。该过程被称为动态拓展。
vector迭代器支持随机访问。
1.2 vector构造函数
std::vector<int> vec1{};//无参构造
std::vector<int> vec2(3, 4);//初始化3个元素4到int型vector中
std::vector<int> vec3(vec2.begin(), vec2.end());//迭代器初始化
std::vector<int> vec4(vec3);//拷贝构造
注意:拷贝构造函数中为深拷贝。
1.3 vector赋值操作
std::vector<float> vec1 = temp_vec;//operator=,深拷贝形式
std::vector<float> vec2;
vec2.assign(3, 8); // n个elem赋值
vec2.assign(vec1.begin(), vec1.end());//区间赋值,这里是区间是迭代器
1.4 vector容量和大小
void Print_vec(std::vector<float>& vec) {
for (auto i : vec) {
cout << i << " ";
}
cout << endl;
}
int main() {
//初始化vector
std::vector<float> vec(5, 8);
std::cout << vec.empty() << std::endl; ;//判断是否为空
std::cout << vec.size() << std::endl; //输出vector容器中元素数量
std::cout << vec.capacity() << std::endl; //输出vector容器中容量
vec.resize(10); //重新指定vec的元素数量,多余的默认0填充
vec.resize(15, 3);//重新指定vec的元素数量的重载,可以指定填充值
Print_vec(vec);
system("pause");
return 0;
}
1.5 vector插入删除
1.6vector数据存取
1.7 vector互换容器swap
目的:实现两个容器内容互换。
实际用途:实现容器容量的收缩,减少内存浪费。
(说明:当一个大容量的vector只有少量元素时,只使用resize重新指定其元素数量并不会改变其容量大小,而使用一个小容量的vector与其进行内容互换的实质是将两个容器的地址互换,此时使用的小容量vector是匿名类型,系统会自动把多余的容量内存释放。)
目的示例:
void Print_vec(std::vector<float>& vec) {
for (auto i : vec) {
cout << i << " ";
}
cout << endl;
}
int main() {
//初始化vector
std::vector<float> vec1(5, 8);
std::vector<float> vec2(9, 4);
Print_vec(vec1);
Print_vec(vec2);
vec1.swap(vec2);
Print_vec(vec1);
Print_vec(vec2);
system("pause");
return 0;
}
实际用途示例:
std::vector<float> vec1(10000, 8);
std::vector<float> vec2(9, 4);
std::cout << vec1.capacity() << std::endl;
std::cout << vec1.size() << std::endl;
vec1.swap(vec2);
std::cout << vec1.capacity() << std::endl;
std::cout << vec1.size() << std::endl;
1.8 vector预留空间
目的:减少vector在动态拓展时的拓展次数,即减少从原空间拷贝到新空间的次数。
接口:vec.reserve(r_size)
int main() {
//初始化vector
//统计开辟空间次数,利用指针指向vec的首地址,当指针地址改变则说明开辟了一次空间
int* p = NULL;
int num = 0;
std::vector<int> vec;
vec.reserve(10000);
for (int i = 0; i < 10000; ++i) {
vec.push_back(i);
if (p != &vec[0]) {
p = &vec[0];
num++;
}
}
std::cout << num << std::endl;
system("pause");
return 0;
}
预留空间与不预留空间的动态拓展次数对比:
2、deque容器(双向队列)
2.1 deque性质
a)双端数组,可以直接在头端进行数据插入。
b)与vector的区别:deque在头端插删数据的效率高于vector,vector访问数据的速度比deque快,即分别在靠头端的数据更改和整体数据访问速度上有速度差异。
c)deque使用多个缓冲区来保存数据,使用中控器来维护指向这些缓冲区的地址。
d)deque迭代器支持随机访问。
2.2 deque构造函数
void Printdq(const std::deque<int>& d) {
//常引用时使用的只读迭代器
for (std::deque<int>::const_iterator c_iter = d.begin(); c_iter != d.end(); ++c_iter) {
//*c_iter = 100;
std::cout << *c_iter << " ";
}
std::cout << std::endl;
}
int main() {
//初始化deque
std::deque<int> deq1{};
deq1.push_back(2);
deq1.push_front(3);
Printdq(deq1);
//n个elem
std::deque<int> deq2(4, 55);
Printdq(deq2);
//拷贝构造1
std::deque<int> deq3(deq2);
Printdq(deq3);
//拷贝构造2
std::deque<int> deq4(deq1.begin(), deq1.end());
Printdq(deq4);
system("pause");
return 0;
}
2.3 deque赋值操作
int main() {
//初始化deque
std::deque<int> deq1(10,7);
Printdq(deq1);
// operator=
std::deque<int> deq2 = deq1;
//assign
std::deque<int> deq3;
deq3.assign(deq2.begin(), deq2.end());
std::deque<int> deq4;
deq4.assign(8, 9);//n个elem assign
system("pause");
return 0;
}
2.4 deque大小操作
注:deque容器没有与vector类似的容量获取接口。
int main() {
//初始化deque
std::deque<int> deq1(10,7);
Printdq(deq1);
std::cout << deq1.empty() << std::endl;
std::cout << deq1.size() << std::endl;
deq1.resize(15);
deq1.resize(20,99);
Printdq(deq1);
deq1.resize(5);
Printdq(deq1);
system("pause");
return 0;
}
2.5 deque插入和删除
int main() {
//初始化deque
std::deque<int> deq1(10,7);
//前后插入
deq1.push_front(3);
deq1.push_back(9);
Printdq(deq1);
//前后删除
deq1.pop_front();
deq1.pop_back();
Printdq(deq1);
//insert指定位置插入
std::deque<int> deq2(4, 5);
deq1.insert(deq1.begin()+1, 2); //在deque第2个位置插入元素2
Printdq(deq1);
deq1.insert(deq1.begin(), 4, 5);//在deque头端插入4个5
Printdq(deq1);
deq1.insert(deq1.begin() + 2, deq2.begin(), deq2.end() - 2);//在deque第3个位置插入deq2的末尾前所有元素
Printdq(deq1);
//删除指定区间元素
deq1.erase(deq1.begin() + 1, deq1.end());
//全部删除
deq1.clear();
std::cout << deq1.empty() << std::endl;
std::cout << deq1.size() << std::endl;
system("pause");
return 0;
}
2.6 deque数据存取
2.7 deque排序操作
目的:实现对deque容器中的元素排序。
void Printdq(const std::deque<int>& d) {
//常引用时使用的只读迭代器
for (std::deque<int>::const_iterator c_iter = d.begin(); c_iter != d.end(); ++c_iter) {
//*c_iter = 100;
std::cout << *c_iter << " ";
}
std::cout << std::endl;
}
int main() {
//初始化deque
std::deque<int> deq1{1,4,2,4,6,1,3};
std::sort(deq1.begin(), deq1.end());
Printdq(deq1);
system("pause");
return 0;
}
3、stack容器(栈)
3.1 性质
a)stack容器中的元素遵循先入后出原则(FILO),只有一个出口。
b)stack容器只有栈顶中的元素才可以被外界使用,不允许有遍历行为。
c)入栈push,出栈pop。
3.2 stack常用接口
int main() {
//构造stack
std::stack<int> st1{};
std::stack<int> st2{};
//数据存取
st1.push(3);
st1.push(4);
st1.push(5);
st1.pop();
std::cout << st1.top() << std::endl;
//大小操作
std::cout << st1.size() << std::endl;
std::cout << st1.empty() << std::endl;
//赋值操作
st2 = st1;
//验证深浅拷贝
st2.pop();
std::cout << st1.top() << std::endl;
//结果为深拷贝
system("pause");
return 0;
}
4、queue容器(队列)
4.1 queue性质
queue遵循先入先出原则(FIFO),具有两个出口,队头和队尾,只能从队尾和队头利用元素(队尾push,队头pop),因此queue不能遍历。
4.2 queue常用接口
5、list容器(双向循环链表)
5.1 list性质
a)链表为非连续的存储结构,其元素之间的逻辑顺序通过指针实现。
b)链表由一系列结点组成,每个节点具有数据域、指针域,分别用于存储当前位置元素和指向下一元素地址。
c)stl中的list容器是双向循环链表,即其指针域具有前后两元素的地址,且第一个元素的前指针指向该链表最后一个元素的地址,最后一个元素的后指针指向该链表第一个元素的地址。
d)list的插入/删除不会造成原有迭代器的失效,迭代器只支持前移和后移(iter++/iter--)。
优点:
1、链表可以对任意位置快速插入和删除(仅需修改对应位置的相关指针指向)。
2、链表采用动态存储分配,不会造成内存浪费和溢出。
缺点:遍历速度较数组慢(链表每次都要通过指针域获取下一元素)。
5.2 list构造函数
int main() {
//构造list
std::list<double> lis1;
lis1.push_back(2);
lis1.push_back(3);
lis1.push_back(4);
std::list<double> lis2(4, 6.);
std::list<double> lis3(lis1.begin(), lis1.end());
std::list<double> lis4(lis3);
system("pause");
return 0;
}
5.3 list赋值和交换
int main() {
//构造list
std::list<double> lis1;
lis1.push_back(2);
lis1.push_back(3);
lis1.push_back(4);
std::list<double> lis2;
std::list<double> lis3;
std::list<double> lis4;
//赋值操作
lis2 = lis1;
lis3.assign(lis1.begin(), lis1.end());
lis4.assign(4, 6.);
//交换
lis1.swap(lis4);
system("pause");
return 0;
}
5.4 list大小操作
int main() {
//构造list
std::list<double> lis1;
lis1.push_back(2);
lis1.push_back(3);
lis1.push_back(4);
std::cout << lis1.size() << std::endl;
std::cout << lis1.empty() << std::endl;
lis1.resize(5);
PrintList(lis1);
lis1.resize(8,10);
PrintList(lis1);
lis1.resize(3);
PrintList(lis1);
system("pause");
return 0;
}
5.5 list插入和删除
int main() {
//构造list
std::list<double> lis1;
std::list<double> lis2(5, 99);
//插入元素
lis1.push_back(2);
lis1.push_back(3);
lis1.push_back(4);
lis1.push_front(6);
lis1.push_front(9);
lis1.pop_back();
lis1.pop_front();
//指定位置插入元素
lis1.insert(lis1.begin(), 3);
lis1.insert(lis1.begin(), 4, 3);
lis1.insert(lis1.begin(), lis2.begin()++,lis2.end()); //只能对迭代器使用++/--
//删除
lis1.erase(lis1.begin());
lis1.erase(lis1.begin(), lis1.begin()++);
lis1.remove(99);
lis1.clear();
PrintList(lis1);
system("pause");
return 0;
}
5.6 list数据存取
int main() {
//构造list
std::list<double> lis1;
std::list<double> lis2(5, 99);
//插入元素
lis1.push_back(2);
lis1.push_back(3);
lis1.push_back(4);
lis1.push_front(6);
lis1.push_front(9);
std::cout << lis1.front() << std::endl;
std::cout << lis1.back() << std::endl;
lis1.back() = 10;
std::cout << lis1.back() << std::endl;
PrintList(lis1);
system("pause");
return 0;
}
5.6 list反转和排序
注:
a)list的反转和排序是由stl提供的list成员函数,即使用sort(iter.begin(),iter.end())是错误的。
b)list排序默认为从小到大,如需获取降序队列,须构造相应的bool模板函数或list元素类型作为输入类型的bool函数
c)如果需要比较自定义类型,同样自行构造相应的bool函数,在其中对自定义类的成员变量进行比较输出bool即可。
template<class T>
bool Max_to_Min(T a, T b) {
return a > b;
}
int main() {
//构造list
std::list<double> lis1;
//插入元素
lis1.push_back(2);
lis1.push_back(3);
lis1.push_back(4);
lis1.push_front(6);
lis1.push_front(9);
//反转
std::cout << "反转前: " << std::endl;
PrintList(lis1);
lis1.reverse();
std::cout << "反转后: " << std::endl;
PrintList(lis1);
//排序
std::cout << "升序排序: " << std::endl;
std::cout << "排序前: " << std::endl;
PrintList(lis1);
lis1.sort();
std::cout << "排序后: " << std::endl;
PrintList(lis1);
std::cout << std::endl;
std::cout << "降序排序: " << std::endl;
std::cout << "排序前: " << std::endl;
PrintList(lis1);
lis1.sort(Max_to_Min<double>);
std::cout << "排序后: " << std::endl;
PrintList(lis1);
system("pause");
return 0;
}
6、set/multiset容器(集合)
6.1 性质
a)所有元素在插入时会被自动排序,set/multiset属于关联式容器,基于二叉树实现。
b)set和multiset区别,set不允许有重复元素,multiset允许重复元素。
c)set不支持随机读取。
6.2 构造和赋值
void pirntSet(const std::set<int>& s) {
for (std::set<int>::const_iterator iter = s.begin(); iter != s.end(); ++iter) {
std::cout << *iter << " ";
}
std::cout << std::endl;
}
int main() {
//构造set/multiset
std::set<int> s1;
std::multiset<int> ms1;
s1.insert(1);
s1.insert(1);
s1.insert(4);
s1.insert(2);
s1.insert(3);
s1.insert(1);
pirntSet(s1);
//拷贝构造
std::set<int> s2(s1);
//operator=
std::set<int> s3;
s3 = s1;
pirntSet(s2);
pirntSet(s3);
system("pause");
return 0;
}
6.3 set大小和交换
6.4 set插入和删除
6.5 set查找和统计
6.6 set与multiset区别
set容器在使用insert接口时,具有pair类型返回值,用于接受迭代器和是否插入成功的bool值。
int main() {
//构造set/multiset
std::set<int> s1;
std::multiset<int> ms1;
s1.insert(1);
ms1.insert(1);
pair<std::set<int>::iterator, bool> ret = s1.insert(1);
if (ret.second) {
std::cout << "插入成功" << std::endl;
}
else {
std::cout << "插入失败" << std::endl;
}
printSet(s1);
printMultiSet(ms1);
system("pause");
return 0;
}
6.7 对组创建
pair<int, bool> p1(3, true);
int a = 10;
double b = 2.;
pair<int, double> p2 = make_pair(a, b);
//pair访问
std::cout << p1.first << "," << p1.second << std::endl;
6.8 set容器排序规则修改
set容器默认从小到大排序,利用仿函数可以修改排序规则。
注:在修改排序规则后再进行insert插值,set不会在修改排序规则后对之前插入的元素排序。
6.8.1 对内置类型排序规则修改
在初始化时进行如下修改即可:
set<int , 包含排序规则仿函数的类名> set1;
//使用类来重载()运算符是为了防止正常的函数使用()出错
class MySort {
public:
bool operator()(const int &a, const int& b) const{
return a > b;
}
};
int main() {
//构造set/multiset
std::set<int, MySort> s1;
s1.insert(1);
s1.insert(4);
s1.insert(3);
s1.insert(5);
s1.insert(2);
s1.insert(7);
std::cout << "set" << std::endl;
for (std::set<int, MySort>::iterator iter = s1.begin(); iter != s1.end(); iter++) {
std::cout << *iter << " ";
}
system("pause");
return 0;
}
6.8.2 对自定义类型排序规则修改
class Person {
public:
Person(string name,int power,double size) {
this->m_Name = name;
this->m_Power = power;
this->m_Size = size;
}
string m_Name;
int m_Power;
double m_Size;
};
class SortPerson {
public:
bool operator()(const Person& a, const Person& b) const{
if (a.m_Power == b.m_Power) {
return a.m_Size > b.m_Size;
}
else
return a.m_Power > b.m_Power;
}
};
int main() {
//构造set/multiset
std::set<Person, SortPerson> s1;
Person p1("Tom", 100, 50);
Person p2("Aris", 80, 50);
Person p3("Tom", 80, 75);
s1.insert(p1);
s1.insert(p2);
s1.insert(p3);
for (std::set<Person, SortPerson>::iterator iter = s1.begin(); iter != s1.end(); iter++) {
std::cout << "m_Name: " << (*iter).m_Name << " m_Power: " << (*iter).m_Power << " m_Size: " << (*iter).m_Size << std::endl;
}
system("pause");
return 0;
}
7、map容器
7.1 map性质
a)map所有元素都是pair,pair的第一个元素为键值key,第二个元素为实值value。(pair参见6.7)
b)map所有元素根据键值自动排序。
c)map/multimap与set类似,属于关联式容器,底层基于二叉树实现。
优点:map可以根据key值快速找到value。
map与maltimap区别:map不允许有重复的key值,multimap运行重复key值。
7.2 map构造、赋值
void printMap(const map<int, float>& m) {
for (map<int, float>::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
cout << (*iter).first << " ," << (*iter).second << endl;;
}
}
int main() {
//构造map
map<int, float> map1;
map1.insert(pair<int, float>(2, 3.));
map1.insert(pair<int, float>(1, 34.));
map1.insert(pair<int, float>(4, 5.));
map<int, float> map2(map1);
map<int, float> map3 = map1;
printMap(map1);
system("pause");
return 0;
}
7.3 map大小和交换
map<int, float> map1;
map1.insert(pair<int, float>(2, 3.));
map1.insert(pair<int, float>(1, 34.));
map1.insert(pair<int, float>(4, 5.));
map<int, float> map2(map1);
map<int, float> map3;
map3.insert(pair<int, float>(3, 15.));
printMap(map1);
cout << map1.size() << endl;
cout << map1.empty() << endl;
map1.swap(map3);
printMap(map1);
7.4 map插入和删除
7.5 map查找、统计
7.6 map排序
map排序与set排序类似,都需要定义相关仿函数才能更改排序顺序。
a)内置类型的map排序顺序更改:
class Mapsort {
public:
bool operator()(const int & p1, const int& p2)const {
return p1 > p2;
}
};
int main() {
//构造map
map<int, float,Mapsort> map1;
map1.insert(pair<int, float>(2, 3.));
map1.insert(pair<int, float>(1, 34.));
map1.insert(pair<int, float>(4, 5.));
map1.insert(pair<int, float>(7, 52.));
map1.insert(pair<int, float>(8, 35.));
for (map<int, float, Mapsort>::iterator iter = map1.begin(); iter != map1.end(); ++iter) {
cout << (*iter).first << " ," << (*iter).second << endl;;
}
cout << endl;
system("pause");
return 0;
}
b)自定义类型的map顺序修改:
class Person {
public:
Person(string name,int power,double size) {
this->m_Name = name;
this->m_Power = power;
this->m_Size = size;
}
string m_Name;
int m_Power;
double m_Size;
};
class SortPerson {
public:
bool operator()(const Person& a, const Person& b) const{
if (a.m_Power == b.m_Power) {
return a.m_Size > b.m_Size;
}
else
return a.m_Power > b.m_Power;
}
};
int main() {
//构造map
map<Person, float, SortPerson> map1;
Person p1("Tom", 324, 12);
Person p2("Asdo", 56, 120);
Person p3("Utuma", 324, 56);
Person p4("Laxiy", 78, 70);
Person p5("Caisax", 56, 86);
map1.insert(pair<Person, float>(p1, 3.));
map1.insert(pair<Person, float>(p2, 34.));
map1.insert(pair<Person, float>(p3, 5.));
map1.insert(pair<Person, float>(p4, 52.));
map1.insert(pair<Person, float>(p5, 35.));
for (map<Person, float, SortPerson>::iterator iter = map1.begin(); iter != map1.end(); ++iter) {
cout << "m_Name:" << (*iter).first.m_Name;
cout << "\tm_Power:" << (*iter).first.m_Power;
cout << "\tm_Size:" << (*iter).first.m_Size;
cout << "\tvalue:" << (*iter).second;
cout << endl;
}
cout << endl;
system("pause");
return 0;
}