一、基础入门知识(泛型编程)
泛型编程: 编辑C++的泛型编程主要通过模板实现,包括函数模板和类模板。C++泛型就是为了代码能够更好的复用,所以一般的小项目,基本用不到的,大的项目用着会很不错的。
函数模板
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
函数模板格式
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
函数模板的实例化
隐式实例化
隐式实例化:让编译器根据实参推演模板参数的实际类型
//函数模板
template <class T>
//模板参数T的类型并不是固定的,通过实际传递的参数来推导T的类型,实例化出一份函数
//template <typename T> 这种写法也是可以的
void Swap(T &num1, T &num2)
{
T tmp = num1; // 使用类型T的临时变量tmp存储num1的值
num1 = num2; // 将num2的值赋给num1
num2 = tmp; // 将tmp的值(即原num1的值)赋给num2
}
void functest()
{
//交换整形
int a = 10, b = 20;
Swap(a, b); // 隐式实例化,将T推导为int类型
cout << "a :" << a << " b :" << b << endl; // 输出交换后的a和b的值
//交换浮点型
float c = 10.55f, d = 3.14f;
Swap(c, d); // 隐式实例化,将T推导为float类型
cout << "c :" << c << " d :" << d << endl; // 输出交换后的c和d的值
}
流程图示例:
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
显式实例化
显式实例化:在函数名后的<>中指定模板参数的实际类型
如Swap< int>(a, b);//显示实例化
//显示指定模板参数类型为int
int a = 10, b = 20;
Swap<int>(a, b);//显示实例化
//显示指定模板参数类型为float
float c = 10.55f, d = 3.14f;
Swap<float>(c, d);//显示实例化
显示指定模板参数类型后,就不再需要编译器根据实参的类型去推断模板参数T的类型了,模板参数类型显示指定是啥就是啥。
类模板
类模板的定义格式
//可以声明多个模板参数
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
示例:
template <class T1, class T2>
class Pair
{
private:
T1 first; // 类型为 T1 的第一个成员变量
T2 second; // 类型为 T2 的第二个成员变量
public:
// 构造函数,使用初始化列表初始化 first 和 second
Pair(T1 f, T2 s) : first(f), second(s) {}
// 成员函数,用于显示 first 和 second 的值
void display() const {
cout << "First: " << first << ", Second: " << second << endl;
}
// 成员函数,返回 first 的值
T1 getFirst() const { return first; }
// 成员函数,返回 second 的值
T2 getSecond() const { return second; }
};
隐式实例化
Pair<int, double> p1(10, 20.5);
Pair<string, int> p2("Example", 42);
p1 和 p2 分别为 Pair<int, double> 和 Pair<string, int> 的隐式实例化对象。
显式实例化
Pair<int, double> p3 = Pair<int, double>(30, 40.5);
p3 是 Pair<int, double> 的显式实例化对象。
代码示例
#include "stdafx.h"
#include <cstring> // 添加这行
template<class T>
T max(T a, T b)
{
return a > b ? a : b;
}
//特化
template<>
char* max(char* a, char* b)
{
return(strcmp(a, b) > 0 ? (a): (b));
}
//比较的两个数据类型不统一,但是输出类型必须为int型
template<class T1,class T2>
int max(T1 a, T2 b)
{
return static_cast<int> (a > b ? a : b);
}
#include"iostream"
using namespace std;
int main()
{
cout <<::max(1, 2) << endl;//作用域加上
cout <<::max(1.5, 3.5) << endl;
cout << ::max('a','b') << endl;
cout << ::max("hello","world") << endl;
const char* s1 = "hello";
const char* s2 = "world";
cout <<::max(s1, s2) << endl;
cout << ::max(1, 2.5) << endl;
return 0;
}
输出结果
二、STL库
定义
标准模板库 STL(Standard Template Library),是 C++ 标准库的一部分,不需要单独安装,只需要 #include 头文件。
STL 的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL 变得非常通用。例如,由于 STL 的 sort() 函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表、容器和数组;
STL 的另一个重要特性是它不是面向对象的。STL 主要依赖于模板而不是封装、继承和虚函数(多态性)—— OOP的三个要素。在 STL 中找不到任何明显的类继承关系,但这正好是使得 STL 的组件具有广泛通用性的底层特征。另外,STL 是基于模板(Template)实现的,只换类型,不换方法,内联函数的使用使得生成的代码短小高效;
STL标准库六大组件
容器
STL容器分为两大类:
- 序列式容器(Sequence Containers)
- 关联式容器(Associative Containers)
数据结构 | 描述 | 实现头文件 |
---|---|---|
向量(vector) | 连续存储的元素 | < vector > |
列表(list) | 由节点组成的双向链表,每个节点包含着一个元素 | < list > |
双队列(deque | 连续存储的指向不同元素的指针所组成的数组 | < deque > |
集合(set) | 由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用域元素对的谓词排列,没有两个不同的元素能够拥有相同的次序。 | < set > |
多重集合(multiset) | 允许存在两个次序相等的元素的集合 | < multiset > |
栈(stack) | 后进先出的值排序 | < stack > |
队列(queue) | 先进先出的值排序 | < queue > |
优先队列(priority_queue) | 存在优先级的队列 | < priority_queue > |
映射(map) | 由{键,值}对组成的集合,以某种作用于键对上的谓词序列 | < map > |
多重映射(multimap) | 允许键对有相等的次序的映射 | < multimap> |
序列式容器
每个元素都有固定位置,取决于插入时机和地点,和元素值无关,如 vector、deque、list 等;
- Vector:将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),数组尾部添加或移除元素非常快速,但是在中部或头部安插元素比较费时;
- Deque:是“double-ended queue”的缩写,可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非常快速,但是在中部安插元素比较费时;
- List:双向链表,不提供随机存取(按顺序走到需存取的元素,O(n)),在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针;
序列容器操作示例
//定义程序入口
#include"stdafx.h"
#include<vector>
#include<list>
#include<queue>
#include<stack>
# include<iostream>
#include "Demo9-1.h"
using namespace std;
struct Display
{
void operator()(int i)
{
cout << i << " " ; //将数据元素一一输出
}
};
int main()
{
int iArr[] = {1,2,3,4,5};
vector<int>iVector(iArr, iArr + 4); //传入首地址和尾地址
list<int>iList(iArr, iArr + 4);
deque<int>iDque(iArr, iArr + 4);
queue<int>iQueue(iDque); //队列,先进先出
stack<int>iStack(iDque); //栈,先进后出
priority_queue<int>iPQueue(iArr, iArr + 4); //优先队列,优先级的问题
/*
for_each 算法 函数原型 : 将 迭代器 范围 内的所有元素 传入 一个参数的 可调用对象 , 逐个遍历 执行上述操作 ;
模板:
template <class InputIt, class Function>
Function for_each(InputIt first, InputIt last, Function f);
InputIt first 参数 :要遍历的 迭代器范围 的 起始迭代器 , first 参数 是指向序列中 第一个元素 的迭代器 ;
这是 " 前闭后开区间 " 的 起始闭区间 ;
InputIt last 参数 : 要遍历的 迭代器范围 的 终止迭代器 , last 参数 是指向序列中 最后一个元素 之后 位置 的迭代器 ;
这是 " 前闭后开区间 " 的 末尾开区间 ;
Function f 参数 : 接收一个参数的可调用对象 , 可以是 一元函数对象 或者 接收一个参数的 普通函数 / Lambda 表达式 ,
将迭代器范围 内的 所有元素 , 传入该 可调用对象 中 ,
*/
for_each(iVector.begin(), iVector.end(), Display());
cout << endl;
for_each(iList.begin(), iList.end(), Display());
cout << endl;
for_each(iDque.begin(), iDque.end(), Display());
cout << endl;
cout << "iQueue:";
while (!iQueue.empty())
{
cout<< iQueue.front() << " ";
iQueue.pop();
}
cout << endl;
cout << "iStacke:";
while (!iStack.empty())
{
cout<< iStack.top() << " ";
iStack.pop();
}
cout << endl;
cout << "iPQueue:";
while (!iPQueue.empty())
{
cout<< iPQueue.top() << " ";
iPQueue.pop();
}
cout << endl;
return 0;
}
vector容器的使用(增删查改)
定义:相当于一个动态数组
移动元素的时间复杂度为O(n)
1、vector末尾的添加移除操作
- vector push_back(10); //在末尾添加10
- vector pop_back(); //删除末尾元素
2、vector任意位置的添加移除操作
- vector.insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置注意第一个参数不能为下标,应为指针注意第一个参数不能为下标,应为指针
- vector.insert(pos,n,elem); /在pos位置插入n个elem元素,无返回值。
- vector.insert(pos,beg,end);//在pos位置插入[beg,end)左闭右开区间的元素,无返回值。
3、删除指定位置的元素
vector.erase(pos); //删除指定位置元素
4、查询元素
cout << “访问元素:” << endl;
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
cout << endl;
5、修改元素值
vector[pos] = elem;//修改pos位置的值为elem
#include "iostream"
#include<vector>
using namespace std;
int main()
{
int iarr[] = {1,2,3,4,5};
vector<int> v1(iarr,iarr+5); //存储1,2,3,4,5
// cout<<"v1中的下标为3的元素为: "<<v1[3]<<endl;
// vector<int> v2(3,10); //存储3个10
// cout<<"v2中的下标为2的元素为: "<<v2[2]<<endl; //v2[2]为10
// vector<int>v3(v1); //用已经构造完成的v1初始化v3
//访问数据
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
/*
* 在末尾对元素进行删除和插入操作
* */
//在末尾插入一个数据
v1.push_back(10);
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
//删除末尾的元素
v1.pop_back();
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
/*
* 在指定的位置插入指定的元素
* */
v1.insert(v1.begin()+3,100);//注意第一个参数不能为下标,应为指针
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
v1.insert(v1.begin()+3,3,1000); //在下标为3的位置插入3个1000
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
int b[] = {40,50,60,70,80,90};
//将指定的区间中的元素插入到指定的位置
v1.insert(v1.begin()+7,b+1,b+5);//将50到80中的元素插入下标为7的位置
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
v1[1] = 99; // 修改第二个元素为99
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
v1.erase(v1.begin() + 4);//删除下标为4的元素
for(int i= 0;i<v1.size();i++)
cout<<v1[i]<<" ";
cout<<endl;
return 0;
}
list双向链表,链表容器的使用(增删查改),频繁插入删除的时候使用
简介:
- list是一个双向链表,可以高效进行删除和插入操作
- list不可以随机存取元素,所以不支持at.(pos)函数与[ ]操作符
- it++(可以)
- it+(不可以)
list对象的默认构造
list< int >istInt; //定义一个存放Int的list容器
list< float >istFloat;
list< string >lstString;
list头尾的添加和删除操作
list.push_back(elem); //在尾部插入一个元素
list.push_front(elem); //在头部插入一个元素
list.pop_back(); //在尾部删除一个元素
list.pop_front(); //在头部删除一个元素
//
// Created by 15053 on 24-7-18.
//
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int> lstInt;
lstInt.push_back(10);//在尾部插入一个10,尾插法
lstInt.push_front(20);//在头部插入一个20,头插法
//构造1个迭代器
list<int>::iterator it;
for(it = lstInt.begin();it != lstInt.end();it++)
cout<<*it<<" ";
cout<<endl;
/* //删除尾部元素
lstInt.pop_back();
for(it = lstInt.begin();it != lstInt.end();it++)
cout<<*it<<" ";
cout<<endl;*/
/* //删除第一个元素
lstInt.pop_front();
for(it = lstInt.begin();it != lstInt.end();it++)
cout<<*it<<" ";
cout<<endl;*/
//返回第一个结点的数
int x = lstInt.front();
cout<<"front="<<x<<endl;
//返回最后一个结点
int y = lstInt.back();
cout<<"back="<<y<<endl;
lstInt.front() = 100; //将第一个结点赋值为100
lstInt.back()= 200; //将最后一个结点赋值为200
for(it = lstInt.begin();it != lstInt.end();it++)
cout<<*it<<" ";
cout<<endl;
return 0;
}
list与迭代器
list.begin();//返回容器中得第一个元素的迭代器
list.end();//返回容器中最后一个元素之后的迭代器
list.rbegin();//返回倒数第一个元素的迭代器
list.rend();//返回倒数最后一个元素的后面的迭代器
//
// Created by 15053 on 24-7-20.
//
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int>lst;
lst.push_back(10);
lst.push_front(20);
lst.push_back(30);
lst.push_back(40);
//20 10 30 40
//list容器的反向迭代器,输出结果应该是40 30 10 20
list<int>::reverse_iterator it1;
for(it1=lst.rbegin();it1!=lst.rend();it1++)
{
cout<<*it1<<" ";
}
return 0;
}
list对象的带参数构造
list(n,elem);//构造函数将n个elem拷贝给本身
list(beg,end);//构造函数将[beg,end]区间中的元素拷贝给本身
list(const list &lst );//拷贝构造函数
//
// Created by 15053 on 24-7-21.
//
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> lst; // 创建一个list对象lst
lst.push_back(10); // 在lst末尾添加元素10
lst.push_back(20); // 在lst末尾添加元素20
lst.push_back(30); // 在lst末尾添加元素30
lst.push_back(40); // 在lst末尾添加元素40
// 现在lst中元素为 10, 20, 30, 40
list<int> lst1(3, 5); // 初始化创建一个list对象lst1,初始化元素个数为3,值为5
// list<int>lst2(lst1.begin()+1,lst1.end()+1);//错误演示,不可以加加操作
// 获取20和30的迭代器并用它们初始化lst2
list<int>::iterator it_start = lst.begin(); // 获取第一个元素10的迭代器
++it_start; // 递增迭代器,指向20
list<int>::iterator it_end = it_start; // 设置it_end为20的迭代器
++it_end; // 将it_end递增到指向30
++it_end; // 将it_end递增到指向30后面的一个位置
list<int> lst2(it_start, it_end); // 使用20和30来初始化lst2
// 遍历并输出lst2
list<int>::iterator it3;
for (it3 = lst2.begin(); it3 != lst2.end(); ++it3)
cout << *it3 << " ";
cout << endl;
// 遍历并输出lst1
list<int>::iterator it2; // 声明一个迭代器it2
for (it2 = lst1.begin(); it2 != lst1.end(); ++it2)
cout << *it2 << " ";
cout << endl;
return 0;
}
list的赋值
list.assign(beg,end);//将[beg,end)区间的数值拷贝复制给本身,注意区间时左闭右开。
list.assign(n,elem);//将n个elem拷贝赋值给本身
list.swap(lst); //将lst与本身的元素互换。
stack栈容器
stack对象的默认构造形式:stack< T >s;
stack< int>stkint;//存放一个int的stack容器
stack< float >stkint;//存放一个float的stack容器
stack< string>stkint;//存放一个string的stack容器
stack的出栈和入栈,Push和pop操作
stack,push(elem); //往栈偷添加一个元素
stack,pop(); //从栈头删除第一个元素,不返回值,时void类型
stack,top();//访问栈顶元素
//
// Created by 15053 on 24-7-22.
//
#include<iostream>
#include<stack>
using namespace std;
//栈的插入删除操作都在栈顶操作
int main()
{
//使用默认构造方式,构造一个stack容器
stack<int>stk;
stk.push(1);
stk.push(3);
stk.push(5);
stk.push(7);
//7
//5
//3
//1
/* //stack容器没有迭代器,因为栈不允许遍历
cout<<stk.top()<<endl; //top函数只返回栈顶元素,不删除元素。
stk.pop(); //删除栈顶元素,出栈
cout<<stk.top()<<endl;
stk.pop(); //删除栈顶元素,出栈
cout<<stk.top()<<endl;
stk.pop(); //删除栈顶元素,出栈
cout<<stk.top()<<endl;*/
while(!stk.empty()) //判断栈是否为空
{
cout<<stk.top()<<endl;
stk.pop();
}
return 0;
}
stack对象的拷贝构造与赋值
stack(const stack &stk);/拷贝构造函数,利用一个已经存在的容器去构造新的
stack&operator = (const stack &stk); //重载等号操作符
stack容器的大小
stack.empty();//判断栈是否为空
stack.size(); //返回栈的大小
//
// Created by 15053 on 24-7-22.
//
#include<iostream>
#include<stack>
using namespace std;
//栈的插入删除操作都在栈顶操作
int main()
{
//使用默认构造方式,构造一个stack容器
stack<int>stk;
stk.push(1);
stk.push(3);
stk.push(5);
stk.push(7);
//7
//5
//3
//1
/* //stack容器没有迭代器,因为栈不允许遍历
cout<<stk.top()<<endl; //top函数只返回栈顶元素,不删除元素。
stk.pop(); //删除栈顶元素,出栈
cout<<stk.top()<<endl;
stk.pop(); //删除栈顶元素,出栈
cout<<stk.top()<<endl;
stk.pop(); //删除栈顶元素,出栈
cout<<stk.top()<<endl;
while(!stk.empty()) //判断栈是否为空
{
cout<<stk.top()<<endl;
stk.pop();
}*/
stack<int>stk2(stk);
while(!stk2.empty()) //判断栈是否为空
{
cout<<stk2.top()<<endl;
stk2.pop();
}
stack<int>stk3 = stk; //调用的拷贝构造函数
stk3 = stk; //调用=重载
cout<<"stk3.size() = "<<stk3.size()<<endl;
return 0;
}
queue容器
默认构造形式
queue< int>queInt //一个存放int的queue容器
queue< float>queFloat//一个存放float的queue容器
queue< string>queString //一个存放string的queue容器
queue容器的出队入队
queue.push(elem); //汪队尾添加元素
queue.pop(); //从队头一处第一个元素
//
// Created by 15053 on 24-7-22.
//
#include "iostream"
#include "queue"
using namespace std;
int main()
{
//默认构造方式构造一个队列容器
queue<int>q1;
//队列只能从队尾入队,队头出队
q1.push(1);
q1.push(3);
q1.push(5);
//queue容器也没有提供迭代器,因为不可以遍历
/*cout<<"q1.front()="<<q1.front()<<endl; //与stack中的top()方法一样,用于访问数据
q1.pop();
cout<<"q1.front()="<<q1.front()<<endl;*/
while(!q1.empty())
{
cout<<"q1.front()="<<q1.front()<<endl;
q1.pop();
}
return 0;
}
queue容器的数据存取
queue.back();//返回最后一个元素
queue.front();//访问队头元素
关联式容器
元素位置取决于特定的排序准则(如大小顺序),和插入顺序无关,如 set、multiset、map、multimap 等。
- Set / Multiset:内部的元素依据其值自动排序,set 内的相同数值的元素只能出现一次,multiset 内可包含多个数值相同的元素,内部由二叉树实现,便于查找;
- Map / Multimap:map 的元素是成对的键值 / 实值,内部的元素依据其值自动排序,map 内的相同数值的元素只能出现一次,multimap 内可包含多个数值相同的元素,内部由二叉树实现,便于查找;
注意:容器类自动申请和释放内存,无需 new 和 delete 操作。
set/multiset容器
简介:
set/multiset容器对象的默认构造
set< int>setInt; //构造一个存放int的set容器
multiset< int>multisetInt; //构造一个存放int的multiset容器
set容器的插入
set.insert(elem); //插入数据,不可以指定位置,因为会默认排序
set.begin(); //返回第一个元素的迭代器
set.end(); //返回最后一个元素的迭代器
set.rbegin(); //返回倒数第一个元素的迭代器
set.rend(); //返回倒数最后一个元素的迭代器
//
// Created by 15053 on 24-7-23.
//
#include "iostream"
#include "set"
using namespace std;
int main()
{
//插入顺序:3 1 7 5
set<int> s1;
s1.insert(3);
s1.insert(1);
s1.insert(7);
s1.insert(5);
set<int>::iterator it; //正向迭代器
for(it = s1.begin();it!=s1.end();it++)
cout<<*it<<" ";
cout<<endl;
//输出1 3 5 7,set容器默认排序为升序
set<int>::reverse_iterator it2; //反向迭代器
for(it2 = s1.rbegin();it2!=s1.rend();it2++)
cout<<*it2<<" ";
cout<<endl;
return 0;
}
set容器的拷贝构造与赋值
set(const set &st); //拷贝构造函数
set& operator= (const set &st);
set.swap(st); //交换两个集合容器
//
// Created by 15053 on 24-7-23.
//
#include "iostream"
#include "set"
using namespace std;
int main()
{
set<int> s1;
s1.insert(3);
s1.insert(1);
s1.insert(7);
s1.insert(5);
set<int>::iterator it; //正向迭代器
for(it = s1.begin();it!=s1.end();it++)
cout<<*it<<" ";
cout<<endl;
//输出1 3 5 7,set容器默认排序为升序
set<int>::reverse_iterator it2; //反向迭代器
for(it2 = s1.rbegin();it2!=s1.rend();it2++)
cout<<*it2<<" ";
cout<<endl;
set<int>s2(s1); //调用拷贝构造函数
set<int >s3; //调用默认拷贝构造函数
s3 = s2;
for(it = s3.begin();it!=s3.end();it++)
cout<<*it<<" ";
cout<<endl;
s3.insert(10); //给s3中插入10,变成1 3 5 7 10
s3.swap(s1); //交换s1与s3
cout<<"s3:";
for(it = s3.begin();it!=s3.end();it++)
cout<<*it<<" ";
cout<<endl;
cout<<"s1:";
for(it = s1.begin();it!=s1.end();it++)
cout<<*it<<" ";
return 0;
}
set容器的删除
set.clear(); //清楚所有元素
set.erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
set.erase(beg,end); //删除区间[beg,end)的所有元素
set.erase(elem); //删除容器中值为elem的元素
//
// Created by 15053 on 24-7-23.
//
#include "iostream"
#include "set"
using namespace std;
int main()
{
set<int> s1;
s1.insert(3);
s1.insert(1);
s1.insert(7);
s1.insert(5);
set<int>::iterator it; //正向迭代器
for(it = s1.begin();it!=s1.end();it++)
cout<<*it<<" ";
cout<<endl;
//输出1 3 5 7,set容器默认排序为升序
set<int>::reverse_iterator it2; //反向迭代器
for(it2 = s1.rbegin();it2!=s1.rend();it2++)
cout<<*it2<<" ";
cout<<endl;
set<int>s2(s1); //调用拷贝构造函数
set<int >s3; //调用默认拷贝构造函数
s3 = s2;
for(it = s3.begin();it!=s3.end();it++)
cout<<*it<<" ";
cout<<endl;
s3.insert(10); //给s3中插入10,变成1 3 5 7 10
s3.swap(s1); //交换s1与s3
cout<<"s3:";
for(it = s3.begin();it!=s3.end();it++)
cout<<*it<<" ";
cout<<endl;
cout<<"s1:";
for(it = s1.begin();it!=s1.end();it++)
cout<<*it<<" ";
cout<<endl;
it = s3.begin(); //迭代器 it 现在指向 s3 中的第一个元素。
s3.erase(it); //删除s1中第一个元素
cout<<"s3:";
for(it = s3.begin();it!=s3.end();it++)
cout<<*it<<" ";
cout<<endl;
return 0;
}
set容器元素排序
set<int,less< int >>setlintA; //采用升序方式排列元素
set< int>相当于set<int,less< int >>
set<int,greater< int >>setlintB; //采用降序方式排列元素
//
// Created by 15053 on 24-7-23.
//
#include "iostream"
#include"set"
using namespace std;
int main()
{
set<int,less<int>>s1; //升序排列
set<int,greater<int>>s2; //降序排列
s1.insert(1);
s1.insert(3);
s1.insert(5);
s2.insert(1);
s2.insert(3);
s2.insert(5);
set<int>::iterator it;
cout<<"S1升序:";
for(it=s1.begin();it!=s1.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
cout<<"S2降序:";
for(it=s2.begin();it!=s2.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
return 0;
}
set容器的查找
set.find(elem); //查找elem元素,返回指向elem元素的迭代器
set.count(elem); //返回容器中值为elem的元素个数,对于set来说要么是1,要么是0.对于multiset来说可能大于1
set.lower_bound(elem); //返回第一个>=elem元素的迭代器
set.upper_bound(elem); //返回第一个>elem元素的迭代器
//
// Created by 15053 on 24-7-23.
//
#include "iostream"
#include"set"
using namespace std;
int main()
{
set<int,less<int>>s1; //升序排列
set<int,greater<int>>s2; //降序排列
s1.insert(1);
s1.insert(3);
s1.insert(5);
s1.insert(8);
s1.insert(7);
s1.insert(6);
s1.insert(10);
s2.insert(1);
s2.insert(3);
s2.insert(5);
set<int>::iterator it;
it = s1.find(3);//返回值为3
cout<<*it<<endl;
it = s1.find(10); //返回值依旧是3
cout<<*it<<endl;
it = s1.find(10); //正确输出
if(it == s1.end())
{
cout<<"can not found it"<<endl;
}
else
{
cout<<*it<<endl;
}
cout<< s1.count(3)<<endl; //输出结果为1
cout<< s1.count(10)<<endl; //输出结果为0
//查找第一个>=6的元素
it = s1.lower_bound(6);
cout<<"查找第一个>=6的元素"<<*it<<endl;
//查找第一个>6的元素
it = s1.upper_bound(6);
cout<<"查找第一个>6的元素"<<*it<<endl;
return 0;
}
set.equal_range(elem)
返回容器中与elem相等上下限的迭代器,上限是闭区间,下线时开区间
函数返回2个迭代器,而这两个迭代器被封装在pair中
pair<set< int>::iterator,set< int>::iterator>pairIt =set.Int.equal_range(5);
pair是什么?
pair为对组,可以将两个值视为一个单元
pair<T1,T2>存放的两个值类型可以相同,也可以不同。
pair.first时第一个值。pair.second是第二个值
//equal_range()
pair<set<int>::iterator,set<int>::iterator> p = s1.equal_range(6);
/*cout<<"查找第一个>=5的元素"<<*p.first<<endl;//p是迭代器,所以输出为*p.first
cout<<"查找第一个>5的元素"<<*p.second<<endl;*/
if(p.first!=s1.end()&&p.first!=s1.end())
{
cout<<"查找第一个>=5的元素"<<*p.first<<endl;
cout<<"查找第一个>5的元素"<<*p.second<<endl;
}
else
{
cout<<"can not find it"<<endl;
}
map容器
map/multimap采用模板类实现,对象的默认构造形式
map<T1,T2>mapTT;
multimap<T1,T2>multimapTT;
如:
map<int,char> mapA;
map<string,float>mapB;
map容器的插入
map.insert(…); //汪容器中插入元素,返回pair
在map中插入元素的两种方式:
1.通过pair的方式插入对象:mapStu.insert(pair<int,string>(3,“小陈”))
2.通过数组的方式插入值:mapStu[3] = “小陈”;
//
// Created by 15053 on 24-7-23.
//
#include <iostream>
#include<map>
using namespace std;
class Student
{
public:
int id;
string name;
Student() //默认构造函数
{}
Student(int id,string name) //带参数构造和函数
{
this->id=id;
this->name=name;
}
};
int main()
{
//构造一个map容器对象 存储Student对象
map<int,Student> stus;//键值对
map<int,string> mapS;
mapS.insert(pair<int,string>(1,"张三")); //3是键,"张三"是值
mapS.insert(pair<int,string>(1,"张四")); //3是键,"张四"是值
return 0;
}
map容器对象获取键对应的值
使用[]
使用find()函数:成功返回对应的迭代器,失败返回end()的返回值
map<int,string>::iterator it = mapS.find(3);
使用at()函数,如果键值不存在会抛出"out_of_range异常"
迭代器
基本概念
什么是迭代器?
迭代器是一种检查容器内元素并且遍历容器内元素的数据类型
迭代器的作用:
迭代器提供对一个容器中的对象的访问方法,并定义了容器中的对象的范围。
为什么需要迭代器?
STL中不同容器的访问方法并不相同,如果没有迭代器,我们就需要记住每种容器的对象访问方法,也就是说我们可以通过 迭代器统一了对所有容器的访问方式。
成员函数 | 功能 |
---|---|
begin() | 返回指向容器中第一个元素的正向迭代器;如果为const类型容器,在函数返回的是正向迭代器 |
end() | 返回指向最后一个元素之后一个位置的中正向迭代器,与begin()结合使用 |
//
// Created by 150 on 24-7-18.
//
#include "iostream"
#include "vector"
using namespace std;
int main()
{
vector <int> vecIntA;
int iArry[] = {100,1,20,30,40};
vecIntA.assign(iArry,iArry+5);
//1、构造一个迭代器对象
vector<int>::iterator it;
//2、让迭代器it指向vecIntA的第一个元素
it = vecIntA.begin();
cout<<*it<<endl; //*it 表示解引用迭代器 it,即获取迭代器当前指向的元素的值
/*
* 解引用:迭代器是一个指针,通过解引用可以获取指针指向的元素
* #include <iostream>
* using namespace std;
* int main()
* {
int value = 42;
int* ptr = &value; // 指针 ptr 指向变量 value 的地址
cout << "value: " << value << endl; // 打印变量 value 的值
cout << "*ptr: " << *ptr << endl; // 解引用 ptr,打印 ptr 所指向的值
return 0;
}
*输出:
* value: 42
* *ptr: 42
* */
//3、通过循环的方式使用迭代器遍历vecIntA中的所有元素
for(it = vecIntA.begin();it!=vecIntA.end();it++) //可以实现自增it++
{
cout<<*it<<" ";
}
cout<<endl;
it = vecIntA.begin();
it = it+2;
cout<<*it<<endl;
return 0;
}