set容器使用
set 基本概念
集合 有序(自动排序,默认从小到大) 元素唯一
例:
#include <iostream>
#include <set>
using namespace std;
set<int> set1; // 从小到大排列
set<int, less<int>> set2; // 从小到大排列
set<int, greater<int>> set3; // 从大到小排列
set容器的插入和遍历操作
set<int> set1; // 从小到大排列
for(int i = 0; i<5; i++)
{
int tmp = rand();
set1.insert(tmp);
}
set1.insert(100);
set1.insert(100);
set1.insert(100);
for(set<int>::iterator it =set1.begin(); it !=set1.end(); it++)
{
cout << *it << " ";
} // 输出 1 3 100 4566 7889 88899
set 容器的删除操作
while (!set1.empty()) // 遍历删除所有元素
{
set<int>::iterator it = set1.begin();
set1.erase(set1.begin()); // 删除首元素
}
set<int, greater<int>> set1; // 从大到小排列
for(int i = 0; i<5; i++)
{
int tmp = rand();
set1.insert(tmp);
}
set1.insert(100);
set1.insert(100);
set1.insert(100);
for(set<int>::iterator it =set1.begin(); it !=set1.end(); it++)
{
cout << *it << " ";
} // 输出 88899 8888 777 555 100 13
set容器在class,自定义类型排序
struct funstudent // 仿函数
{
bool operator()(const student &left, const student &right)
{
if(left.age < right.age)
{
return true;
}
else
{
return false;
}
}
}
void main()
{
student s1("s1", 31);
student s1("s2", 22);
student s1("s3", 44);
student s1("s4", 11);
set<student, funstudent> set1; // 必须借用仿函数实现
set1.insert(s1);
set1.insert(s2);
set1.insert(s3);
set1.insert(s4);
//遍历
for(set<student, funstudent>::iterator it = set1.begin(), it != set1.end(), it++)
{
cout << it->age <<endl;
} // 输出 11 22 31 44
}
使用pair 来判断插入的结果
// 注:相同的元素插入会失败
set<student, funstudent> set1;
pair<set<student, funstudent>::iterator, bool> pair1 = set1.insert(s1);
if(pair.second == true)
{
cout << "插入s1成功" <<endl;
}
else
{
cout << "插入s1失败" <<endl;
}
set容器的find查找操作
set<int> set1;
for(int i = 0; i<10; i++)
{
set1.insert(i+1);
}
for(set<int>::iterator it = set1.begin(); it!=set1.end(); it++)
{
cout << *it <<endl ; //1 2 3 4 5 6 7 8 9 10
}
set<int>iterator it0 =set1.find(5);
cout << *it0 <<endl; // 5
int num =set1.count(5);
cout<< num <<endl; // 1
// 把元素5删除掉
set1.erase(5);
pair<set<int>::iterator, set<int>::iterator> pair1 = set1.equal_range(5);
set<int>::iterator it3 =pair1.first; 输出大于等于5的元素
cout << *it3 <<endl; // 5 // 如果擦除5 ,则输出6
set<int>::iterator it4 =pair1.second; 输出大于5 的元素
cout << *it4 <<endl; // 6 //如果擦除5 ,则输出6
vector容器使用
vector容器常见使用场景
#include <vector>
using namespace std;
vector<int> v1;
cout << "length" << v1.size() <<endl; // 0
v1.push_back(1);
v1.push_back(3);
v1.push_back(5);
cout << "length" << v1.size() <<endl; // 3
// 1 3 5
v1.front() // 获取头部元素 1 v1.front() = 1; //修改头部元素
v1.back() //获取尾部元素 v1.back() = 5; //修改尾部元素
while(v1.size() > 0) // 遍历并删除所有元素
{
v1.pop_back(); // 删除尾部元素
}
vector 的初始化方式
//方式一
vector<int> v1;
v1.push_back(1);
v1.push_back(3);
v1.push_back(5);
//方式二
vector<int> v2 = v1;
//方式三
vector<int> v3(3, 9); // 存放3个元素,每个元素的值是9
vector 的遍历
vector<int> v1(10); //提前把内存准备好
for(int i=0; i<10; i++)
{
v1[i] = i + 1;
}
for(int i = 0; i < 10; i++)
{
printf("%d ", v1[i]);
}
vector<int> teData; //不提前准备内存
teData.push_back(1);
teData.push_back(2);
for (int i = 0; i < teData.size(); i++)
{
cout << teData[i] << " ";
}
cout << std::endl; // 1 2
//push_back 的强化记忆
vector<int> v1(2); //占用index 1,2
v1.push_back(100); //从index 2开始插入
v1.push_back(200); //从index 3开始插入
//输出 0 0 100 200 大小为 4
用迭代器遍历容器 vector
vector<int>::const_iterator
vector<int>::const_reverse_iterator
vector<int> v1(10); //提前把内存准备好
for(int i=0; i<10; i++)
{
v1[i] = i + 1;
}
//正向遍历
for(vector<int>::iterator it = v1.begin(); it!=v1.end(); it++)
{
cout << *it << " "; // 1 2 3 4 5 6 7 8 9 10
}
//逆序遍历
for(vector<int>::reverse_iterator rit = v1.rbegin(); rit!=v1.rend(); rit++)
{
count << *rit << " "; // 10 9 8 7 6 5 4 3 2 1
}
vector的删除
vector<int> v1(10);
for(int i=0; i<10; i++)
{
v1[i] = i + 1;
}
//区间删除
v1.erase(v1.begin(), v1.begin()+3); //输出 4 5 6 7 8 9 10
//根据元素的位置,指定位置删除
v1.erase(v1.begin()); //删除第一个元素 , 在前面的基础上输出 5 6 7 8 9 10
//v1.erase(v1.begin() + 1); //删除第二个元素,总大小继续减1
//删除指定元素
std::remove(v1.begin(), v1.end(), 3); //将容器中为3的元素全部删除,但容器总容量不变
// 删除最后一个元素
vector<int> v2{ 1,2,3,4,5 };
v2.pop_back(); //删除最后一个元素,但总容量不变
for(int i=0; i<v2.size(); i++)
{
cout << v2[i] << endl;
}
//输出: 1 2 3 4
//根据元素的值删除
v1[1] = 2;
v1[3] = 2; // 5 2 7 2 9 10
for(vector<int>::iterator it = v1.begin(); it!=v1.end(); )
{
if(*it == 2)
{
it = v1.erase(it);
//当删除迭代器所指向的元素的时候,erase删除元素会让it自动向下移动,所以it++写在下面
}
else
{
it++;
}
} // 输出 5 7 9 10
vector的插入与清空
vector<int> v1;
v1.insert(v1.begin(), 100);
printf("data=%d\n", v1.front()); //100
printf("%d\n", v1.size()); //1
v1.clear();
printf("%d\n", v1.size()); // 0
queue容器使用
队列中基本数据类型
#include <iostream>
#include <queue>
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
cout << "队头元素" <<q.front() <<endl; //1
cout << "队列的大小" << q.size() <<endl; //3
while( !q.empty())
{
int tmp = q.front();
cout << tmp << " ";
//或者
//cout << q.front() <<endl;
//q.pop();
} // 输出 1 2 3
队列的算法和容器的分离
teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
//普通常量存储
queue<teacher> s;
s.push(t1);
s.push(t2);
s.push(t3);
while( !s.empty())
{
teacher tmp = s.front();
cout << age <<endl;
s.pop();
}
teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
//指针类型存储
queue<teacher *> s;
s.push(&t1);
s.push(&t2);
s.push(&t3);
while( !s.empty())
{
teacher *p = s.front();
cout << p->age <<endl;
s.pop();
}
map容器使用
#include <iostream>
#include <map>
//map<key, value> key 是唯一的,而且只能对应一个 value
map<int, string> map1;
map容器的插入操作
//方法1
map1.insert(pair<int, string>(1, "teacher01"));
//方法2
map1.insert(make_pair(3, "teahcer01"));
//方法3
map1.insert(map<int, string>::value_type(5, "teacher01"));
//方法4
map1[7] = "teacher07";
map容器的遍历操作
for(map<int, string>::iterator it =map1.begin(); it !=map1.end(); it++)
{
cout << it->first << "\t" << it->second <<endl;
}
map容器的删除操作
while(!map1.empty())
{
map<int, string>::iterator it = map1.begin();
map1.erase(it);
}
判断是否插入成功
(1)方式一
前3种方法插入都是用这种方式判断:
pair<map<int, string>::iterator, bool> mypair = map1.insert(pair<int, string>(1, "teacher01");
if(mypair.second == true)
{
cout<< "key 插入成功" <<endl;
}
(2)方式二
map1[7] = "teacher07";
map1[7] = "teacher77"; // 不会插入失败, 只会覆盖,输出 teacher77
map的查找操作:
map<int, string>::iterator it2 = map1.find(100);
if(it2 == map1.end())
{
cout << "key 100 的值 不存在" <<endl;
}
else
{
cout <<it2->first << "\t" << it2->second <<endl;
}
// equal_range
pair<map<int, string>::iterator, map<int, string>::iterator> mypair = map1.equal_range(5);
// 第一个迭代器 >=5 的位置
//第二个迭代器 >5 的位置
if( mypair.first == map1.end())
{
cout << ">=5的位置不存在" <<endl;
}
else
{
cout << mypair.first->first <<"\t" <<mypair.first->second <<endl;
}
if( mypair.second == map1.end())
{
cout << ">=5的位置不存在" <<endl;
}
else
{
cout << mypair.second->first <<"\t" <<mypair.second->second <<endl;
}
stack容器用法
栈模型
#include <iostream>
#include <stack>
using namespace std;
stack<int> s;
入栈
for(int i =0; i<10; i++)
{
s.push(i+1);
}
cout << "栈的大小" << s.size() <<endl;
出栈
while( !s.empty())
{
int tmp = s.top(); //获取栈元素
cout << tmp << " ";
s.pop(); // 弹出栈顶元素
} // 输出 10 9 8 7 6 5 4 3 2 1
用法一
teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
stack<teacher> s;
s.push(t1);
s.push(t2);
s.push(t3);
while( !s.empty())
{
teacher tmp = s.top();
cout << age <<endl;
s.pop();
}
用法二
teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
stack<teacher *> s;
s.push(&t1);
s.push(&t2);
s.push(&t3);
while( !s.empty())
{
teacher *p = s.top();
cout << p->age <<endl;
s.pop();
}
list (双向链表)容器使用
list的初始化操作
#include <iostream>
#include <list>
list<int> l;
cout << "list的大小" <<l.size() <<endl; // 0
for(int i = 0; i<10; i++)
{
l.push_back(i); //从尾部插入元素,尾插法
}
cout << "list的大小" <<l.size() <<endl;
list<int>::iterator it = l.begin();
while ( it != l.end())
{
cout << *it << " ";
it++;
}
//输出 0 1 2 3 4 5
// list不能随机访问
it = l.begin();
it++;
it++;
it++;
it = it +5; // 错误,不支持随机访问
list的插入操作
l.insert(it, 100);
for(list<list>::iterator it = l.begin(); it!=l.end(); i++)
{
cout << *it << " "; // 输出 0 1 2 100 3 4 5
}
// 结论: 链表的节点index 序号是从0号位置开始
list 的删除操作
// 0 1 2 3 4 5
list<int>::iterator it1 = l.begin();
list<int>::iterator it2 = l.begin();
it2++;
it2++;
it2++;
l.erase(it1, it2); // 删除操作的区间为 左闭右开
for(list<list>::iterator it = l.begin(); it!=l.end(); i++)
{
cout << *it << " "; // 输出 3 4 5
}
//删除第一个元素 0 1 2 3 4 5
l.erase(l.begin()); //输出: 1 2 3 4 5
//删除元素1 0 1 1 1 2 3
l.remove(1) //输出: 0 2 3
容器在类中的值拷贝
简介
容器类值的插入是属于拷贝, 所以要使用 拷贝构造函数和 =运算符重载。
使用举例
class teacher
{
public:
teacher(char * name, int age)
{
m_pname = new char[strlen(name) +1];
strcpy(m_pname, name);
m_age = age;
}
~teacher
{
delete[] m_pname;
m_pname = NULL;
m_age = 0;
}
private:
char *m_pname;
int m_age;
};
void main()
{
teacher t1("t1", 31);
vector<teacher> v1;
v1.push_back(t1); // 如果不重写拷贝构造函数和赋值运算符重载,则会因为内存无法拷贝出错
}
解决:
// 拷贝构造函数
teacher(const teacher &obj)
{
m_pname = new char[strlen(obj.m_pname) + 1];
strcpy(m_pname, obj.m_pname);
m_age = obj.m_age;
}
// 赋值运算符重载
teacher operator=(const teacher &obj)
{
// 1) 把旧的内存释放掉
if(m_pname != NULL)
{
delete[] m_pname;
m_pname = NULL;
m_age = 0;
}
// 2) 分配内存
m_pname = new char[strlen(obj.m_pname) + 1];
// 3) 拷贝数据
strcpy(m_pname, obj.m_pname);
m_age = obj.m_age;
return *this;
}
deque容器(双端数组)使用
deque的初始化操作
#include <iostream>
#include <deque>
using namespace std;
deque<int> d1;
d1.push_back(1);
d1.push_back(3);
d1.push_back(5);
d1.push_front(-11);
d1.push_front(-33);
d1.push_front(-55); // -55 -33 -11 1 3 5
cout << "头部元素" << d1.front() <<endl; // -55
cout << "尾部元素" << d1.back() <<endl; // 5
//删除元素
d1.pop_front();
d1.pop_back(); // -33 -11 1 3
deque的查找操作
deque<int>::iterator it = find(d1.begin(), d1.end(), -33);
if( it != d1.end())
{
cout << "-33数组的下标是" << distance(d1.begin(), it) <<endl; // d1.begin()为偏移量
}
else
{
cout << "没有找到值为-33的元素" << endl;
}
优先级队列
容器 priority_queue优先级队列分为 最大优先级队列和最小优先级队列
头文件
#include "queue"
初始化
priority_queue<int> p1; // 默认情况是 最大优先级队列
priority_queue<int, vector<int>, less<int>> p2; //手动设置最大优先级队列
priority_queue<int, vector<int>, greater<int>> p3; //手动设置最小优先级队列
最大优先级队列的初始化和遍历
p1.push(33);
p1.push(11);
p1.push(55);
p1.push(22);
cout << "队头元素" << p1.top() <<endl;
cout << "队列的大小" << p1.size() <<endl;
while(p1.size() > 0)
{
cout << p1.top() << " ";
p1.top();
}
// 输出 55 33 22 11
最小优先级队列的初始化和遍历
p3.push(33);
p3.push(11);
p3.push(55);
p3.push(22);
cout << "队头元素" << p3.top() <<endl;
cout << "队列的大小" << p3.size() <<endl;
while(p1.size() > 0)
{
cout << p3.top() << " ";
p3.top();
}
// 输出 11 22 33 55
迭代器:
//迭代器相当于指针,可以遍历出容器中的元素
for(vector<int>::iterator it = v1.begin; it!=v1.end; it++)
{
cout<< *it <<endl;
}
teacher t1,t2,t3;
vector<teacher > v1
v1.push_back(t1);
v1.push_back(t2);
v1.push_back(t3);
//迭代器相当于指针,可以遍历出容器中的元素
for(vector<int>::iterator it = v1.begin(); it!=v1.end(); it++)
{
cout<< (*it).age <<endl;
}
总结
各大容器的特点:
类型 | vector | deque | list | set | multiset | map | multimap |
---|---|---|---|---|---|---|---|
内存结构 | 单端数组 | 双端数组 | 双向链表 | 二叉树 | 二叉树 | 二叉树 | 二叉树 |
是否可随机存储 | 是 | 是 | 否 | 否 | 否 | 对key而言是 | 否 |
元素搜寻速度 | 慢 | 慢 | 非常慢 | 快 | 快 | 对key而言快 | 对key而言快 |
快速安插移除 | 尾端 | 头尾两端 | 任何位置 | — | - ---- | — | ---- |