[TOC]
# set
Set的特性是所有元素都会根据元素的键值自动被排序。Set的元素不像map那样可以同时拥有实值和键值,set的元素即是键值又是实值。Set不允许两个元素有相同的键值。
我们可以通过set的迭代器改变set元素的值吗?不行,因为set元素值就是其键值,关系到set元素的排序规则。如果任意改变set元素值,会严重破坏set组织。换句话说,set的iterator是一种const\_iterator.
set拥有和list某些相同的性质,当对容器中的元素进行插入操作或者删除操作的时候,操作之前所有的迭代器,在操作完成之后依然有效,被删除的那个元素的迭代器必然是一个例外。
# multiset
multiset特性及用法和set完全相同,唯一的差别在于它允许键值重复。
set和multiset的底层实现是红黑树,红黑树为平衡二叉树的一种。
# 常用api
## 构造函数
~~~
set<T> st;//set默认构造函数:
mulitset<T> mst; //multiset默认构造函数:
set(const set &st);//拷贝构造函数
~~~
## 赋值操作
~~~
set&operator=(const set &st);//重载等号操作符
swap(st);//交换两个集合容器
~~~
## 大小操作
~~~
size();//返回容器中元素的数目
empty();//判断容器是否为空
~~~
## 插入和删除操作
~~~
insert(elem);//在容器中插入元素。
clear();//清除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem);//删除容器中值为elem的元素。
~~~
~~~
#include <set> //multset也是这个头文件
void printSet(set<int> &s) {
for (set<int>::iterator it = s.begin(); it != s.end(); ++it) {
cout << *it << " ";
}
cout << endl;
}
void test02() {
set<int> s;
s.insert(4);
s.insert(8);
s.insert(9);
s.insert(10);
s.insert(11);
printSet(s);
}
~~~
## 自定义排序
~~~
//定义个排序规则
struct myfunc
{
bool operator()(int v1,int v2)
{
return v1 > v2;
}
};
void printSet2(set<int, myfunc> &s)
{
for (set<int, myfunc>::iterator it = s.begin(); it != s.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
}
//改变set容器的规则,变为降序(从大到小)
void test02()
{
set<int, myfunc> s;
s.insert(4);
s.insert(8);
s.insert(2);
s.insert(10);
s.insert(7);
printSet2(s);
}
~~~
~~~
void print(int v)
{
cout << v << " ";
}
//不能通过算法排序
void test04()
{
multiset<int> s;
s.insert(4);
s.insert(8);
s.insert(2);
s.insert(2);
s.insert(7);
//自身规则进行排序,从小到大
//不能通过算法排序来排序关联式容器的元素
//sort(s.begin(), s.end());
for_each(s.begin(), s.end(), print);
cout << endl;
}
~~~
## 判断是否插入成功
~~~
pair<set<int,myfunc>::iterator, bool> ret=s.insert(11);
if (ret.second) {
cout << "插入成功" << endl;
} else {
cout << "插入失败" << endl;
}
~~~
## 查找
~~~
find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
1. count(key);//查找键key的元素个数
2. lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
3. upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
~~~
~~~
set<int> s;
s.insert(4);
s.insert(8);
s.insert(6);
s.insert(9);
s.insert(7);
set<int>::iterator it=s.find(10);
if (it == s.end())
{
cout << "查找失败" << endl;
}
else
{
cout << "查找成功:" << *it << endl;
}
//查找大于等于2的最小的数
it = s.lower_bound(2);
if (it == s.end())
{
cout << "查找失败" << endl;
}
else
{
cout << "查找成功:" << *it << endl;
}
//查找大于2的最小的数
it = s.upper_bound(2);
if (it == s.end())
{
cout << "查找失败" << endl;
}
else
{
cout << "查找成功:" << *it << endl;
}
//返回大于等于2的两个最小的数,如果有2那么就返回2和大于2的最小数
pair<set<int>::iterator,set<int>::iterator> ret=s.equal_range(2);
cout << *(ret.first) << endl;
cout << *(ret.second) << endl;
multiset<int> s1;
s1.insert(4);
s1.insert(4);
s1.insert(4);
s1.insert(9);
s1.insert(7);
cout << s1.count(4) << endl;
~~~
## 存储对象
~~~
//存储对象时,需要告诉set容器规则
class Maker
{
public:
Maker(string name,int age)
{
this->name = name;
this->age = age;
}
public:
string name;
int age;
};
struct Makerfunc
{
bool operator()(const Maker &m1,const Maker &m2)
{
return m1.age > m2.age;
}
};
void test06()
{
set<Maker, Makerfunc> s;
s.insert(Maker("aaa", 18));
s.insert(Maker("bbb", 19));
s.insert(Maker("ccc", 20));
s.insert(Maker("ddd", 21));
s.insert(Maker("eee", 22));
for (set<Maker, Makerfunc>::iterator it = s.begin(); it != s.end(); ++it)
{
cout << "Name:" << it->name << " Age:" << it->age << endl;
}
}
~~~
- c语言
- 基础知识
- 变量和常量
- 宏定义和预处理
- 随机数
- register变量
- errno全局变量
- 静态变量
- 类型
- 数组
- 类型转换
- vs中c4996错误
- 数据类型和长度
- 二进制数,八进制数和十六进制数
- 位域
- typedef定义类型
- 函数和编译
- 函数调用惯例
- 函数进栈和出栈
- 函数
- 编译
- sizeof
- main函数接收参数
- 宏函数
- 目标文件和可执行文件有什么
- 强符号和弱符号
- 什么是链接
- 符号
- 强引用和弱引用
- 字符串处理函数
- sscanf
- 查找子字符串
- 字符串指针
- qt
- MFC
- 指针
- 简介
- 指针详解
- 案例
- 指针数组
- 偏移量
- 间接赋值
- 易错点
- 二级指针
- 结构体指针
- 字节对齐
- 函数指针
- 指针例子
- main接收用户输入
- 内存布局
- 内存分区
- 空间开辟和释放
- 堆空间操作字符串
- 内存处理函数
- 内存分页
- 内存模型
- 栈
- 栈溢出攻击
- 内存泄露
- 大小端存储法
- 寄存器
- 结构体
- 共用体
- 枚举
- 文件操作
- 文件到底是什么
- 文件打开和关闭
- 文件的顺序读写
- 文件的随机读写
- 文件复制
- FILE和缓冲区
- 文件大小
- 插入,删除,更改文件内容
- typeid
- 内部链接和外部链接
- 动态库
- 调试器
- 调试的概念
- vs调试
- 多文件编程
- extern关键字
- 头文件规范
- 标准库以及标准头文件
- 头文件只包含一次
- static
- 多线程
- 简介
- 创建线程threads.h
- 创建线程pthread
- gdb
- 简介
- mac使用gdb
- setjump和longjump
- 零拷贝
- gc
- 调试器原理
- c++
- c++简介
- c++对c的扩展
- ::作用域运算符
- 名字控制
- cpp对c的增强
- const
- 变量定义数组
- 尽量以const替换#define
- 引用
- 内联函数
- 函数默认参数
- 函数占位参数
- 函数重载
- extern "C"
- 类和对象
- 类封装
- 构造和析构
- 深浅拷贝
- explicit关键字
- 动态对象创建
- 静态成员
- 对象模型
- this
- 友元
- 单例
- 继承
- 多态
- 运算符重载
- 赋值重载
- 指针运算符(*,->)重载
- 前置和后置++
- 左移<<运算符重载
- 函数调用符重载
- 总结
- bool重载
- 模板
- 简介
- 普通函数和模板函数调用
- 模板的局限性
- 类模板
- 复数的模板类
- 类模板作为参数
- 类模板继承
- 类模板类内和类外实现
- 类模板和友元函数
- 类模板实现数组
- 类型转换
- 异常
- 异常基本语法
- 异常的接口声明
- 异常的栈解旋
- 异常的多态
- 标准异常库
- 自定义异常
- io
- 流的概念和类库结构
- 标准io流
- 标准输入流
- 标准输出流
- 文件读写
- STL
- 简介
- string容器
- vector容器
- deque容器
- stack容器
- queue容器
- list容器
- set/multiset容器
- map/multimap容器
- pair对组
- 深浅拷贝问题
- 使用时机
- 常用算法
- 函数对象
- 谓词
- 内建函数对象
- 函数对象适配器
- 空间适配器
- 常用遍历算法
- 查找算法
- 排序算法
- 拷贝和替换算法
- 算术生成算法
- 集合算法
- gcc
- GDB
- makefile
- visualstudio
- VisualAssistX
- 各种插件
- utf8编码
- 制作安装项目
- 编译模式
- 内存对齐
- 快捷键
- 自动补全
- 查看c++类内存布局
- FFmpeg
- ffmpeg架构
- 命令的基本格式
- 分解与复用
- 处理原始数据
- 录屏和音
- 滤镜
- 水印
- 音视频的拼接与裁剪
- 视频图片转换
- 直播
- ffplay
- 常见问题
- 多媒体文件处理
- ffmpeg代码结构
- 日志系统
- 处理流数据
- linux
- 系统调用
- 常用IO函数
- 文件操作函数
- 文件描述符复制
- 目录相关操作
- 时间相关函数
- 进程
- valgrind
- 进程通信
- 信号
- 信号产生函数
- 信号集
- 信号捕捉
- SIGCHLD信号
- 不可重入函数和可重入函数
- 进程组
- 会话
- 守护进程
- 线程
- 线程属性
- 互斥锁
- 读写锁
- 条件变量
- 信号量
- 网络
- 分层模型
- 协议格式
- TCP协议
- socket
- socket概念
- 网络字节序
- ip地址转换函数
- sockaddr数据结构
- 网络套接字函数
- socket模型创建流程图
- socket函数
- bind函数
- listen函数
- accept函数
- connect函数
- C/S模型-TCP
- 出错处理封装函数
- 多进程并发服务器
- 多线程并发服务器
- 多路I/O复用服务器
- select
- poll
- epoll
- epoll事件
- epoll例子
- epoll反应堆思想
- udp
- socket IPC(本地套接字domain)
- 其他常用函数
- libevent
- libevent简介