C++ STL之set集合容器

set容器使用一种称为红黑树的平衡二叉检索树的数据结构,来组织泛化的元素数据。作为节点键值的元素的插入,必须确保每个子树根节点的键值大于左子树所有节点的键值,小与右子树所有节点的键值。不会将重复的键值插入容器,也不需指定具体的插入位置,而按元素在树中首尾关联关系,进行位置的检索、删除和插入。
元素数据的检索,使用的是二叉检索树的中序遍历算法,检索的效率高于vector,deque和list等容器,并能把元素数据从小到大遍历出来,因此set容器蕴含了元素的有序性。

  1. 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)。所以,从根节点到叶结点的路径中,最长路径不会超过最短路径的两倍。
    为什么要进行“着色”?
    利用颜色值做二叉树的平衡对称性的检查,只要插入节点“着色”满足红黑二色的规定,最长和最短路径不会相差太远,红黑树的节点分布就能大体上达致平衡。
  2. 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容器是一个有序关联容器,所包含的元素也必须是唯一的,不能插入重复的元素。由于使用了红黑树这种特殊的平衡二叉检索树管理元素数据,具有高效的元素插入、删除和检索。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值