set容器使用一种称为红黑树的平衡二叉检索树的数据结构,来组织泛化的元素数据。作为节点键值的元素的插入,必须确保每个子树根节点的键值大于左子树所有节点的键值,小与右子树所有节点的键值。不会将重复的键值插入容器,也不需指定具体的插入位置,而按元素在树中首尾关联关系,进行位置的检索、删除和插入。
元素数据的检索,使用的是二叉检索树的中序遍历算法,检索的效率高于vector,deque和list等容器,并能把元素数据从小到大遍历出来,因此set容器蕴含了元素的有序性。
- set技术原理
C++STL对红黑树稍作修改,以获取更高的性能和适于容器的泛化。如下图,颜色域M_color是一个bool变量,红色为true,黑色为false。M_parent、M_left和M_right均为节点的指针变量,构成了一个三叉链表的结构,之所以添加M_parent变量,是考虑到需要频繁上溯父节点的缘故。
例如,将一组整数21,30,10,8,37,46,29,5,16,19,15和32一次插入生成一个红黑树。
性质:
(1)根节点是黑色。
(2)其他节点是红色或黑色。
(3)每个红色节点的左右子节点都必须是黑色。
(4)每条从叶子节点到根节点的路径,都包含相同数目的黑色节点。
从(3)可知:红黑树的任何路径都不会出现两个相邻的红色节点,否则就存在一对父子节点都是红色。
再由性质(4),设从根节点到叶节点的黑色节点数为n,则最短路径为全黑,即“黑→黑→…→黑”路径,最短路径长度为n-1;而最长路径为“红→黑→红→黑→…→黑”,即最长路径为2(n-1)。所以,从根节点到叶结点的路径中,最长路径不会超过最短路径的两倍。
为什么要进行“着色”?
利用颜色值做二叉树的平衡对称性的检查,只要插入节点“着色”满足红黑二色的规定,最长和最短路径不会相差太远,红黑树的节点分布就能大体上达致平衡。 - set应用基础
创建set对象参考vector,不再重复,没意思
2.1元素的插入
set并没有固定的所谓尾部插入push_back函数,元素的插入一般使用insert进行动态检索插入。
(1)pair<iterator,bool> insert(const value_type& v)
将元素v插入set容器,要求v值不与set容器的任何元素重复,否则插入失败。返回一个pair对象,提供所插入元素的迭代器位置和true/false插入成功标志。
不多说,都在代码里
#include <set>
#include <QCoreApplication>
#include <iostream>
#include<QString>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
set<int> s;
s.insert(10);
pair<set<int>::iterator,bool> p =s.insert(19);
if(p.second) //必须要解释一下这个pair了,第一个参数即first代表插入的值,第二个参数即second表示是否插入成功
{
cout << "插入新元素" << *(p.first) << endl;
}
else
{
cout << "已存在该元素,不重复插入" << endl;
}
return a.exec();
}
运行结果:
2.2元素的遍历、反向遍历和搜索
set容器的迭代器提供了访问内部红黑树中元素的操作,通常用begin和end函数找出首元素和末元素,然后通过迭代器的“++”进行中序遍历,再由迭代器的“*”操作,由小到大取出元素值。
反向遍历也一样,逆中序遍历从而将元素从大到小遍历出来。
set容器提供了一个应用红黑树进行搜索的函数find,返回的迭代器值为搜索到的元素位置,如果函数不存在,则返回一个end结束元素位置。
代码:
#include <set>
#include <QCoreApplication>
#include <iostream>
#include<QString>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
set<int> s;
s.insert(10);
s.insert(15);
s.insert(11);
s.insert(17);
s.insert(13);
s.insert(19);
s.insert(19); //不会重复输入
set<int>::iterator i,iend;
iend = s.end();
cout << "顺序:";
for(i=s.begin();i!=iend;i++)
{
cout << *i << " ";
}
cout << endl;
set<int>::reverse_iterator ri,rend;
rend=s.rend();
cout << "逆序:";
for(ri=s.rbegin();ri!=rend;ri++)
{
cout << *ri << " ";
}
cout << endl;
int v=13;
set<int>::iterator i_v = s.find(v); //搜索13
cout << *i_v << endl;
v=60;
i_v = s.find(v); //搜索不存在的元素60,即返回end给i_v
if(i_v != s.end())
{
cout << *i_v << endl;
}
return a.exec();
}
运行结果:
2.3补充
multiset多重集合容器和set一样,也使用红黑树组织元素数据,只是multiset允许将重复的元素键值插入,而set容器不允许,实现方法和set相同。
2.4小结
set容器是一个有序关联容器,所包含的元素也必须是唯一的,不能插入重复的元素。由于使用了红黑树这种特殊的平衡二叉检索树管理元素数据,具有高效的元素插入、删除和检索。