概述
set
实现原理:
set 的特性是,所有元素都会根据元素的键值自动被排序。set 的元素不像 map 那样可以同时拥有实值(value)和键值(key),set 元素的键值就是实值,实值就是键值,set不允许两个元素有相同的值。
set 底层是通过红黑树(RB-tree)来实现的,由于红黑树是一种平衡二叉搜索树,自动排序的效果很不错,所以标准的 STL 的 set 即以 RB-Tree 为底层机制。又由于 set 所开放的各种操作接口,RB-tree 也都提供了,所以几乎所有的 set 操作行为,都只有转调用 RB-tree 的操作行为而已。
用法:
一些用法与上面的类似,这里就不全部列出来了
初始化:
set<int> s;
set<int, mycompare> s;
//mycompare其实就是排序规则,查找等操作全部是按照它来,最好用仿函数吧
赋值操作:
s.swap(s1); //交换集合s和s1
s = s1;
插入操作:
s.insert(10); //往集合中插入10
删除操作:
s.erase(s.begin(), s.end()-1); //删除……,返回下一个元素的迭代器
查找操作:
s.find(10);
//查找元素10是否存在,如果存在,返回其迭代器,否则返回s.end()
s.lower_bound(10);
//查找第一个大于等于10的迭代器,如果没有,则返回s.end()
s.upper_bound(10);
//查找第一个大于10的迭代器,如果没有,则返回s.end()
s.equal_range(10);
//返回 s.lower_bound(10);和s.upper_bound(10);的迭代器,以对组的方式返回,一样需要判断s.end()
对组:
pair<iterator, iterator> pair<int, int>等等等…… 可以 = 赋值,另外也可以使用make_pair函数
EG: pair<set::iterator, set::iterator> ret = s.equal_range(10);
我们可以通过first 以及 second 两个公有函数来访问pair的两个值,即ret.first……
仿函数(函数对象,C++中可以使用这个来取代函数指针,毕竟挺强大的~):
仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。仿函数(functors)在C++标准中采用的名称是函数对象(function objects)。
仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,但是函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求–函数指针,无法和STL其他组件搭配,产生更灵活变化。仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象。
对于重载了()操作符的类,可以实现类似函数调用的过程,所以叫做仿函数,实际上仿函数对象仅仅占用1字节,因为内部没有数据成员,仅仅是一个重载的方法而已。实际上可以通过传递函数指针实现类似的功能,但是为了和STL内部配合使用,他提供了仿函数的特性。
函数对象超出了函数的概念,函数对象可以保存函数调用的状态:
-
如果是普通函数且我们想获取调用次数,那我们可以使用全局变量,但是真正开发中,我们是避免去使用全局变量的,因为在多线程环境中我们需要去进行加锁解锁;
- 而仿函数(函数对象)是一个类,我们只需在里面声明一个变量即可。
- 像for_each、sort(algorithm)这类函数,我们也可以传入函数对象(模板的思想)
EG:
class mycompare
{
public:
bool operator()(int v1, int v2){return v1 > v2;}
};
int main(void)
{
set<int, mycompare> s;
}
-
一元仿函数、二元仿函数……:根据参数的个数来称呼
-
谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个对象,那么叫二元谓词,谓词可作为一个判断式。
multiset
multiset的特性以及用法和 set 完全相同,唯一的差别在于它允许键值重复,因此它的插入操作采用的是底层机制是 RB-tree 的 insert_equal()(即大于等于走右边) 而非 insert_unique()。
map
实现原理:
map的特性是,所有元素都会根据元素的键值自动被排序。map 的所有元素都是 pair,同时拥有实值(value)和键值(key)。pair 的第一元素被视为键值,第二元素被视为实值。
map不允许两个元素拥有相同的键值。由于 RB-tree 是一种平衡二叉搜索树,自动排序的效果很不错,所以标准的STL map 即以 RB-tree 为底层机制。又由于 map 所开放的各种操作接口,RB-tree 也都提供了,所以几乎所有的 map 操作行为,都只是转调 RB-tree 的操作行为。
用法:
map的很多方法和set是类似的。
初始化:
map<int, string> m;
map<int, string, mycompare> m;
//mycompare其实就是排序规则,查找等操作全部是按照它来,最好用仿函数吧
插入:
map<int, string> mapStu;
mapStu.insert(pair<int, string>(3,"body1"));
//第一种方法,通过pair的方式插入对象
mapStu.insert(make_pair(1, "body2"));
//第二种方法,通过make_pair创建pair的方式插入对象
mapStu.insert(map<int, string>::value_type(5, "body3"));
//第三种方法,通过value_type的方式插入对象
mapStu[2] = "body4";
//第四种方法,通过数组的方式插入值
//**前三种方法区别不大,用数组方式插入时,如果发现key不存在,则会创建pair并插入到map中,如果存在,那么会修改其实值**
//**注意,使用cout << mapStu[6] << endl; 时,如果通过[]方式去访问一个不存在的key,那么map会将这个访问的key插入到map中,且value会采取默认值**
访问:
map<int, string>::iterator it;
通过it->first 访问键值,通过it->second 访问实值
pair<int, string> p;
通过p.first 访问键值,通过p.second 访问实值,这里要和迭代器区分开!
查找操作:
map<int, string> m;
m.find(10);
//查找键值10是否存在,如果存在,返回其迭代器,否则返回m.end()
m.lower_bound(10);
//查找第一个大于等于10的迭代器,如果没有,则返回m.end()
m.upper_bound(10);
//查找第一个大于10的迭代器,如果没有,则返回m.end()
m.equal_range(10);
//返回 m.lower_bound(10);和m.upper_bound(10);的迭代器,以对组的方式返回,一样需要判断m.end()
multimap
multimap 的特性以及用法与 map 完全相同,唯一的差别在于它允许键值重复,因此它的插入操作采用的是底层机制 RB-tree 的 insert_equal() 而非 insert_unique。
注意:
multimap的仿函数使用和set、multiset、map的不一样!!
class Mycompare
{
public:
bool operator()(int v1, int v2)const //这里必须加const
{
return v1>v2;
}
};
int main(void)
{
multimap<int,string, mycompare> m;
}
另外,multimap不支持[],即不能使用s[10]=10这类操作!!
hash_set 与 hash_multiset
hash_set 底层数据结构为 hash 表,无序,不重复。hash_multiset 底层数据结构为 hash 表,无序,不重复。(貌似是用拉链法)
hash_map 与 hash_multimap
hash_map 底层数据结构为 hash 表,无序,不重复。hash_multimap 底层数据结构为 hash 表,无序,不重复。
其它
-
STL容器所提供的都是值(value)寓意,而非引用(reference)寓意,也就是说当我们给容器中插入元素的时候,容器内部实施了拷贝动作,将我们要插入的元素再另行拷贝一份放到容器中,而不是将原数据元素直接放进容器中,也就是说我们提供的元素必须那个被拷贝。
-
通常STL不会抛出异常,需要使用者传入正确参数
-
STL容器使用时机:
-
vector:单端数组,可随机存取(有时候称为直接访问),元素搜寻速度慢,元素安插移除在尾端比较快
-
deque:双端数组,可随机存取,元素搜寻速度慢,元素安插移除在头尾两端比较快
-
list:双向链表,不可随机存取,元素搜寻速度非常慢,元素安插移除在任何位置都快
-
set:红黑树,不可随机存取,元素搜寻速度快
-
multiset:红黑树,不可随机存取,元素搜寻速度快
-
map:红黑树,对key而言是可随机存取,对key而言元素搜寻速度快
-
multimap:红黑树,不可随机存取,对key而言元素搜寻速度快
-
-
函数对象(仿函数)
很多东西前面已经讲了,这里就不重复了。-
STL内建了一些函数对象。分为:算法类函数对象,关系类函数对象,逻辑类函数对象。这些函数对象所产生的对象,用法和一般的函数完全相同,
当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件 #include。-
函数对象适配器(重点)(functional库)
函数对象适配器是完成一些配接工作,这些配接工作包括绑定(bind)、否定(negate),以及对一般函数或成员的修饰,使其成为函数对象。-
绑定适配器:bind1st、bind2nd
-
功能:将一个二元函数对象转变为一元函数对象
-
区别:
-
bind1st(叫bind first)是将传进来的参数绑定为函数对象的第一个参数
-
bind2nd(叫bind second)是将传进来的参数绑定为函数对象的第二个参数
-
例子:
-
-
-
-
-
class Myprint : public binary_function<int, int, void>
//注意,使用绑定配接器必须使我们的函数对象继承自binary_function,
binary_function是一个模板类,我们需要传入<参数1类型, 参数二类型, 返回类型>
{public:
void operator()(int v, int val) const //注意,这里必须使用const修饰
{
cout << v + val << endl;
}
}
……
int addNum = 200;
for_each(v.begin(), v.end(), bind2st(Myprint, addNum));
-
取反适配器:not1、not2
-
功能:对谓词的返回进行取反
-
区别:not1是对一元谓词进行取反,而not2是对二元谓词进行取反
-
例子:
-
class Mycompare : public binary_function<int, int, bool>
//注意,使用not2配接器必须使我们的函数对象继承自binary_function,
我们这里是二元的,因此是继承自binary_function
{public:
bool operator()(int v1, int v2) const
//注意,这里必须使用const修饰
{
return v1 > v2;
}
}
class Mycompare5 : public binary_function<int, bool>
//注意,这里继承的父类是unary_function
{public:
bool operator()(int v1) const
//注意,这里必须使用const修饰
{
return v1 > 5;
}
}
……
sort(v.begin(), v.end(), not2(Mycompare));
find_if(v.befin(), v.end(), not1(Mycompare5));
-
关于find_if算法(使用方法参考上面的例子)
这个算法的功能是返回第一个满足条件的迭代器 -
函数对象适配器:ptr_fun
-
功能:把函数转变为函数对象
-
例子:
-
void myPrint(int val1, int val2)
{
cout << val1 + val2 << endl;
}
……
for_each(v.begin(), v.end(), bind2st(ptr_fun(myPrint), 10));
-
成员函数适配器 mem_fun、mem_fun_ref
-
功能:如果容器中存放的是对象或者对象指针,我们for_each算法打印的时候又想用类自己提供的打印函数
-
例子
class Stu { public: void Print(int val1, int val2); } …… vector<Stu> v1; for_each(v1.begin(), v1.end(), mem_fun_ref(&Stu::Print)); //注意使用的方法 vector<Stu*> v2; for_each(v2.begin(), v2.end(), mem_fun(&Stu::Print)); //注意mem_fun和mem_fun_ref的使用,必须加&符号!! //当容器内是对象时,使用mem_fun_ref;当容器内是对象指针时,使用mem_fun。
-
-
常用的算法
-
常用的遍历算法
-
for_each(iterator beg, iterator end, _callback);
-
transform(iterator beg1, iterator end1, iterator beg2, _callback)
- 将指定容器区间元素搬运到另一个容器中,注意另一个容器的空间必须是初始化过的,可以使用resize,但不可以使用reserve,参考二者的区别
- _callback是搬运的方法,例子如下:
class Myplus {public: int operator()(int val){return val; } } …… transform(v1.begin(), v1.end(), v2.begin(), Myplus());
-
-
常用的查找算法
-
find(iterator beg, iterator, value);
- 需要注意的是(下面也一样),自定义对象间的比较要求我们重载==运算符,如bool operator ==(const Person p)const{}
-
adjacent_find(iterator beg, iterator end, _callback);
- 查找相邻重复元素,_callback为回调函数或者谓词,返回相邻元素的第一个位置的迭代器
-
bool binary_search(iterator beg, iterator end, value);
- 二分查找,在无序序列中不能使用,查找成功返回true,否则返回false
-
find_if(iterator beg, iterator end, _callback);
- 查找第一个满足条件的元素(_callback,谓词),并返回其迭代器,如果没有当然是返回end()
-
count(iterator beg, iterator end, value);
- 统计元素的出现个数并返回(int)
-
count_if(iterator beg, iterator end, _callback);
- 统计满足条件的元素的个数并返回(int)
-
-
常用排序算法
-
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest, _callback);
- 将两个已排序(必须都是从小到大或从大到小)合并,并存储到另一个容器中
-
sort(iterator beg, iterator end, _callback);
- 容器元素排序
-
random_shuffle(iterator beg, iterator end);
- 对指定范围内的元素随机调整次序
-
reverse(iterator beg, iterator end);
- 反转指定范围的元素
-
-
常用拷贝和替换算法
-
copy(iterator beg, iterator end, iterator dest);
- 将容器内指定范围的元素拷贝到另一容器中
-
replace(iterator beg, iterator end, oldvalue, newvalue);
- 将容器内指定范围的旧元素修改为新元素
-
replace_if(iterator beg, iterator end, _callback, newvalue);
- 将容器内指定范围满足条件的元素替换为新元素
-
swap(container c1, container c2);
- 互换两个容器的元素
-
-
常用算术生成算法
-
accumulate(iterator beg, iterator end, value);
- 计算容器中=元素累计总和+value
-
fill(iterator beg, iterator end, value);
- 向容器中添加元素
-
-
常用的集合算法
-
set_intersection(iterator beg1, iterator end1, iterator iterator beg2, iterator end2, iterator dest);
- 求两个集合的交集,返回一个迭代器,该迭代器指向最后一个元素的下一个元素
-
set_union(iterator beg1, iterator end1, iterator iterator beg2, iterator end2, iterator dest);
- 求两个集合的并集,返回一个迭代器,该迭代器指向最后一个元素的下一个元素
-
set_difference(iterator beg1, iterator end1, iterator iterator beg2, iterator end2, iterator dest);
- 求两个集合的差集,返回一个迭代器,该迭代器指向最后一个元素的下一个元素
-
-
最后
以上就是伶俐音响为你收集整理的编程语言C/C++(七)—— STL(二)的全部内容,希望文章能够帮你解决编程语言C/C++(七)—— STL(二)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复