set的性质和一些操作
使用set和multiset时要包含set头文件,set的底层是红黑树,所以是不支持随机访问的类型,那么迭代器就只能++,–。红黑树就是一个要求不那么严格的平衡二叉树,对于红黑树的内容等后期自己学习一下也会写一篇文章,现在只需知道set和multiset底层的实现都是红黑树即可。
对于set是不支持容器中有重复的元素的,但是multiset容器中可以有相同的元素。
这就用到了一个键值对pair的概念,下边就是pair类型的两种创建方式。
pair<string, int> p("小王", 22); //pair的两种创建方式
pair<string, int> p1 = make_pair("小罗", 18); //这一种的用的更多
p.first; //取p的第一个元素,返回 小王
p.second; //取p的第二个元素, 返回 22
可以看到在set
的insert函数返回值是一个pair类型的键值对,第一个参数是迭代器类型,第二个参数布尔类型判断是否插入成功。
那么对于multiset
的insert函数返回值就是一个迭代器类型,不是pair类型就没有第二个参数,所以无论插入的数据是否重复都会插入成功。
set的一些常用操作
int main() {
set<int> r_b_tree_set; //默认构造
set<int> r_b_tree_set1(r_b_tree_set); //拷贝构造
r_b_tree_set = r_b_tree_set1; //重载运算符赋值
r_b_tree_set.size(); //返回容器的大小
r_b_tree_set.empty(); //判空
r_b_tree_set.swap(r_b_tree_set1); //交换两个容器的元素
r_b_tree_set.insert(10); //插如操作默认升序排列
r_b_tree_set.insert(5); //不可以插入重复的元素,其中有一个对组pair<A,B> A是迭代器类型,B是布尔类型,
//判断是否插入成功,如果本来容器中没有相同元素返回true插入成功,否则返回false插入失败
bool a = r_b_tree_set.insert(50).second; //表示获取插入函数的第二个参数,bool类型的是否成功。
r_b_tree_set.insert(30);
r_b_tree_set.erase(r_b_tree_set.begin());//(他的迭代器也不支持随机访问 红黑树 )删除迭代器位置的元素
r_b_tree_set.erase(++r_b_tree_set.begin(),r_b_tree_set.end());//删除两个迭代器之间的数据
r_b_tree_set.erase(30); //删除容器中值等于30的数据,如果传的值在容器中不存在,则什么操作也不做。
if (r_b_tree_set.find(2) != r_b_tree_set.end()) { //查找容器中值为 2 的元素,如果找到返回迭代器的位置,没找到就返回end()位置。
cout << "找到元素" << endl;
}
else cout << "容器中没有val = 5 的元素" << endl;
int val_num = r_b_tree_set.count(30);//统计容器中值等于30的元素个数 对于set容器因为不允许重复的数据,则返回0或者1
system("pause");
return 0;
}
set容器和multiset容器都是插入时自动升序排列的所以在代码中也提供了一种实现降序排列的方式,并且如果是自定义数据类型,必须使用这种方法来实现set和multiset容器(要重写排序方法)。
class Dog {
public:
Dog(string name, int age) {
this->dog_name = name;
this->dog_age = age;
}
string dog_name;
int dog_age;
};
class DownSortForDogAge {
public:
bool operator()(const Dog& d1,const Dog& d2) const {//仿函数
return d1.dog_age > d2.dog_age; //按降序排列
}
};
class DownSortForSet {
public:
bool operator()(int val1, int val2) const {//仿函数
return val1 > val2; //实现int的降序排列
}
};
void printfIntSet(const set<int, DownSortForSet>& s) {
for (set<int, DownSortForSet>::const_iterator it = s.begin(); it != s.end(); it++) {
cout <<*it<<endl;
}
cout << endl;
}
void printfDogSet(const set<Dog, DownSortForDogAge>& s) {
for (set<Dog, DownSortForDogAge>::const_iterator it = s.begin(); it != s.end(); it++) {
cout <<"狗的名字: " << it->dog_name<<" \t狗的年龄:" << it->dog_age << endl;
}
cout << endl;
}
int main() {
set<int,DownSortForSet> r_b_tree_set; //尖括号中传入的是类类型,所以DownSortForSet必须是个类,那么类中写一个
//仿函数,来实现降序排列,
r_b_tree_set.insert(30);
r_b_tree_set.insert(20);
r_b_tree_set.insert(100);
r_b_tree_set.insert(5);
r_b_tree_set.insert(120);
printfIntSet(r_b_tree_set);
set<Dog,DownSortForDogAge> dog_set;//自定义数据类型实现插入到set容器中
Dog d1("aa", 15);
Dog d2("bb", 12);
Dog d3("cc", 16);
Dog d4("dd", 10);
Dog d5("ee", 18);
Dog d6("ff", 30);
Dog d7("gg", 5);
dog_set.insert(d1);
dog_set.insert(d2);
dog_set.insert(d3);
dog_set.insert(d4);
dog_set.insert(d5);
dog_set.insert(d6);
dog_set.insert(d7);
printfDogSet(dog_set);
system("pause");
return 0;
}
那么对于set的仿函数要写一个类而list排序的仿函数写一个函数就可以了这个问题,我的理解(理解片面,请多指正):因为list的排序是在sort函数中进行的,函数的小括号里边传的参数不允许是类类型,所以自己写一个独立的函数来实现就行了,但是对于set来说,他的排序是在插入之前就要进行的,所以要在尖括号中指定排序规则,尖括号的数据类型应该是一个类类型,比如:int,string这种的,所以说对于排序规则不能只是写一个函数,要写一个类,来实现仿函数。
multiset与set的区别就是插入的时候可以插入重复的数据,因为他的插入函数返回值是一个迭代器类型,不是pair类型,其他的一些常用方法大致与set类似这里就不在赘述。
unordered_set的性质和一些操作
之所以会有unordered这种类型的寄存器出现,是为了更快的查找操作,相对于以前的set之类的虽然是没有顺序的但是查找效率是要远远高于以前的有序容器的。
unordered_set和unordered_multiset底层是用哈希来实现的,哈希又叫散列表,对于查找操作速度非常快,他是将每个元素用哈希函数映射到哈希表中,对于一个哈希算法的好坏,主要取决于他本身的哈希函数以及处理冲突的方式,具体的一些细节在这里不在展开。
对于unordered_set的插入操作不可以插入重复的数据,那么同样对于unordered_multiset是可以插入重复的数据。
unordered就意味着无序,这个无序是说不是按照我们插入的顺序的先后来显示的,而是他底层自己有一个哈希映射的操作,具体是先插入的在前边还是在后边我们无法确定。那么对于底层是Hash是不支持随机访问的,这就是说迭代器只能++,–。
unordered_set的一些常用操作
没有排序操作,如果再有排序操作不如直接用set,那样就舍本逐末了。
对于unordered_multiset也大致类似。
int main() {
unordered_set<int> hash_set; //默认构造
unordered_set<int> hash_set1(hash_set); //拷贝构造
hash_set1 = hash_set; //赋值
hash_set.insert(50); //插入操作
hash_set.insert(10);
hash_set.insert(30);
hash_set.insert(60);
hash_set.erase(10); //删除值为10的数
if (hash_set.find(20) == hash_set.end()) { //查找容器中值为20的数,找到返回迭代器位置,没找到返回迭代器end()位置
cout << "没找到" << endl;
}
else cout << "找到了" << endl;
hash_set.size(); //容器大小
hash_set.empty(); //判空
system("pause");
return 0;
}
unordered_multiset和unordered_set大致用法一样,只是一个可以插入重复数据,一个不可以插入重复数据,就不在赘述。