C++ STL --set()与multiset()

需要包含头文件:# include <set>

set和multiset会根据特定的排序准则,自动将元素进行排序。不同的是后者允许元素重复而前者不允许。

自动排序的主要优点在于使二叉树搜寻元素具有良好的性能,在其搜索函数算法具有对数复杂度。但是自动排序也造成了一个限制,不能直接改变元素值,因为这样会打乱原有的顺序,要改变元素的值,必须先删除旧元素,再插入新元素。所以sets和multisets具有以下特点:

  • 不提供直接用来存取元素的任何操作元素
  • 通过迭代器进行元素的存取。

1. set是一个集合容器,其中所包含的元素是唯一的,集合中的元素按一定的顺序排列。元素插入过程是按排序规则插入,所以不能指定插入位置。

2. set采用红黑树变体的数据结构实现,红黑树属于平衡二叉树。在插入操作和删除操作上比vector快。

                                           

3. set不可以直接存取元素。(不可以使用at.(pos)与[]操作符)。

4. multiset与set的区别:set支持唯一键值,每个元素值只能出现一次;而multiset中同一值可以出现多次。

                                 

5. 不可以直接修改set或multiset容器中的元素值,因为该类容器是自动排序的。如果希望修改一个元素值,必须先删除原有的元素,再插入新的元素。

1.构造函数

set<int> a; //定义一个int类型的集合a
//set<int> a(10); //error,未定义这种构造函数
//set<int> a(10, 1); //error,未定义这种构造函数
set<int> b(a); //定义并用集合a初始化集合b
set<int> b(a.begin(), a.end()); //将集合a中的所有元素作为集合b的初始值
除此之外,还可以直接使用数组来初始化向量:
int n[] = { 1, 2, 3, 4, 5 };
set<int> a(n, n + 5);              //将数组n的前5个元素作为集合a的初值

multiset<int> a; //定义一个int类型的集合a
//multiset<int> a(10); //error,未定义这种构造函数
//multiset<int> a(10, 1); //error,未定义这种构造函数
multiset<int> b(a); //定义并用集合a初始化集合b
multiset<int> b(a.begin(), a.end()); //将集合a中的所有元素作为集合b的初始值
除此之外,还可以直接使用数组来初始化向量:

int n[] = { 1,1, 2,2, 3,3, 4,4, 5,5 };
multiset<int> a(n, n + 10);              //将数组n的前5个元素作为集合a的初值

代码

# include <iostream>
# include <set>
using namespace std;

//该模板函数, 支持各种容器到数据打印
template <class iterator>
void show(iterator begin, iterator end) 
{
    for (iterator it = begin; it != end; ++it)
    {
        cout << *it << endl;
    }
}

//使用迭代器需要添加关键字typename,该模板函数, 支持各种容器到数据打印
template <class container>
void print(container con) 
{
    for (typename container::iterator it = con.begin(); it != con.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main()
{
    set<int> a; //定义一个int类型的集合a
    cout <<"a.empty() = "<< a.empty() << endl;
    //set<int> a(10); //error,未定义这种构造函数
    //set<int> a(10, 1); //error,未定义这种构造函数
    int n[] = { 1, 2, 3, 4, 5 };       //除此之外,还可以直接使用数组来初始化向量
    set<int> b(n, n + 5);              //将数组n的前5个元素作为集合a的初值
    cout << "b(n, n + 5) = ";
    print(b);
    set<int> c(b); //定义并用集合b初始化集合c
    cout << "c(b) = ";
    print(c);
    set<int> d(++c.begin(), --c.end()); //将集合c中的第二个到倒数第二个之间的元素作为集合d的初始值
    cout << "d(++c.begin(), --c.end()) =  ";
    print(d);    


    multiset<int> h; //定义一个int类型的集合a
    cout << "h.empty() = " << h.empty() << endl;
    int m[] = { 1,1,2,2,3,3,4,4,5,5 };  //除此之外,还可以直接使用数组来初始化向量
    multiset<int> i(m, m + 10);    //将数组m的前10个元素作为集合i的初值
    cout << "i(n, n + 10) = ";
    print(i);
    multiset<int> g(i); //定义集合g,并用集合i初始化集合g
    cout << "g(i) = ";
    print(g);
    multiset<int> k(++g.begin(), --g.end()); //将集合c中的第二个到倒数第二个之间的元素作为集合k的初始值
    cout << " k(++g.begin(), --g.end()) =  ";
    print(k);
 }

运行结果

2. 增加函数

  • 在容器中插入元素:st.insert(const T& x);
  • 任意位置插入一个元素: st.insert(iterator it, const T& x);
  • 插入[first,last)间元素 :st.insert( const value_type *first, const value_type *last);

代码

# include <iostream>
# include <set>
using namespace std;

//使用迭代器需要添加关键字typename,该模板函数, 支持各种容器到数据打
template <class container>
void print(container con) 
{
    for (typename container::iterator it = con.begin(); it != con.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main()
{
    set<int> st;

    //在容器中插入元素
    st.insert(6);
    st.insert(7);
    //在迭代指针it处插入一个元素
    set<int>::iterator it = ++st.begin();
    st.insert(it, 2);
    // 插入[first,last)之间的元素
    int s[] = {1,2,3,4,5};
    st.insert(s, s+5);
    print(st);


    multiset<int> mulset; //定义一个int类型的集合a

    //在容器中插入元素
    mulset.insert(4);
    mulset.insert(4);
    //在迭代指针it处插入一个元素
    set<int>::iterator iter = ++mulset.begin();
    mulset.insert(iter, 4);
    // 插入[first,last)之间的元素
    mulset.insert(s, s + 5);
    print(mulset);
 }

运行结果

3.删除函数

  • 删除容器中值为elem的元素: st.erase(const T& elem);
  • 删除it迭代器所指的元素: st.erase(iterator it);
  • 删除区间[first,last]之间的所有元素: st.erase(iterator first, iterator last);
  • 清空所有元素: st.clear();

代码

# include <iostream>
# include <set>
using namespace std;

//使用迭代器需要添加关键字typename,该模板函数, 支持各种容器到数据打
template <class container>
void print(container con) 
{
    for (typename container::iterator it = con.begin(); it != con.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main()
{
    set<int> st;
    for (int i = 0; i < 8; i++)
        st.insert(i);
    cout << "原st ";
    print(st);
    //删除容器中值为elem的元素
    st.erase(4);
    cout << "删除容器中值为4的元素 ";
    print(st);
    //任意位置删除一个元素
    set<int>::iterator it = st.begin();
    st.erase(it);
    cout << "删除容器中第一个元素 ";
    print(st);
    //删除[first,last]之间的元素
    st.erase(st.begin(), ++st.begin());
    cout << "删除容器中第一个到第二个之间的元素 ";
    print(st);


    //清空所有元素
    st.clear();

    //clear, display st
    cout << "clear,st: ";
    print(st);

 }

运行结果

4. 迭代器

  • 开始迭代器指针:st.begin();
  • 末尾迭代器指针:st.end(); //指向最后一个元素的下一个位置
  • 指向常量的开始迭代器指针: st.cbegin(); //意思就是不能通过这个指针来修改所指的内容,但还是可以通过其他方式修改的,而且指针也是可以移动的。
  • 指向常量的末尾迭代器指针: st.cend();
  • 反向迭代器指针,指向最后一个元素: st.rbegin();
  • 反向迭代器指针,指向第一个元素的前一个元素: st.rend();
  • 返回最后一个key<=keyElem元素的迭代器: st.lower_bound(keyElem);
  • 返回第一个key>keyElem元素的迭代器: st.upper_bound(keyElem);
  • 返回容器中key与keyElem相等的上下限的两个迭代器,这两个迭代器被放在对组(pair)中: st.equal_range(keyElem);
  • 返回容器中元素值等于key的元素个数 : st.count(keyElem);
  • 查找功能,返回元素值等于key的迭代器指针:find(keyElem);

代码

# include <iostream>
# include <set>
using namespace std;

//使用迭代器需要添加关键字typename,该模板函数, 支持各种容器到数据打
template <class container>
void print(container con) 
{
    for (typename container::iterator it = con.begin(); it != con.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main()
{
    set<int> st;
    st.insert(1);
    st.insert(2);
    st.insert(3);
    st.insert(4);
    st.insert(5);
    cout << "st: ";
    print(st);
    cout << "*(st.begin()): " << *(st.begin()) << endl;
    cout << "*(st.end()): " << *(--st.end()) << endl;
    cout << "*(st.cbegin()): " << *(st.cbegin()) << endl;
    cout << "*(st.cend()): " << *(--st.cend()) << endl;
    cout << "*(st.rbegin()): " << *(st.rbegin()) << endl;
    cout << "*(st.rend()): " << *(--st.rend()) << endl;
    cout << "*(st.lower_bound(2)): " << *(st.lower_bound(2)) << endl;
    cout << "*(st.upper_bound(2)): " << *(st.upper_bound(2)) << endl;
    pair<set<int>::iterator, set<int>::iterator> t_pair = st.equal_range(2);
    cout << "*(t_pair.first): " << *(t_pair.first) << endl;
    cout << "*(t_pair.second): " << *(t_pair.second) << endl;
    cout << "st.count(5): " << st.count(5) << endl;
    set<int>::iterator it = st.find(3);
    st.erase(it);
    st.erase(st.find(4));
    cout << "st.erase(st.find(3)) and st.erase(st.find(4)): ";
    print(st);
    cout << endl;

    return 0;

 }

运行结果

5. 容量函数

  • 容器大小: st.size();
  • 容器最大容量: st.max_size();
  • 容器判空: st.empty();
  • 查找键key的元素个数: st.count(key);

代码

# include <iostream>
# include <set>
using namespace std;

//使用迭代器需要添加关键字typename,该模板函数, 支持各种容器到数据打
template <class container>
void print(container con) 
{
    for (typename container::iterator it = con.begin(); it != con.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main()
{
    set<int> st;
    for (int i = 0; i < 6; i++)
    {
        st.insert(i);
    }

    cout << "元素大小: " << st.size() << endl;
    cout << "元素最大容量: " << st.max_size() << endl;
    cout << "键2的元素个数: " << st.count(2) << endl;
    if (st.empty())
        cout << "元素为空" << endl;

    return 0;

 }

运行结果

6. 其他函数

  • 交换两个同类型容器的元素: swap(set&, set&); 或 lst.swap(set&);

代码

# include <iostream>
# include <set>
using namespace std;

//使用迭代器需要添加关键字typename,该模板函数, 支持各种容器到数据打
template <class container>
void print(container con) 
{
    for (typename container::iterator it = con.begin(); it != con.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main()
{
    set<int> st1;
    st1.insert(1);
    st1.insert(2);
    st1.insert(3);
    set<int> st2;
    st2.insert(4);
    st2.insert(5);
    st2.insert(6);
    //交换两个容器的元素
    //swap(st1, st2); //ok
    st1.swap(st2);

    //display st1
    cout << "交换后的st1: ";
    set<int>::iterator it;
    print(st1);
    //display st2
    cout << "交换后的st2: ";
    print(st2);

    return 0;

 }

运行结果

总结

可以看到,set 与序列式容器的用法有以下几处不同:

  • set 只支持默认构造函数和拷贝构造函数,没有其它重载的构造函数。
  • set 只能使用insert的两种重载函数插入,不支持push_back()和push_front()函数。
  • set 能不通过迭代器,只通过元素值来删除该元素。
  • set 容器不提供下标操作符。为了通过键从 set 中获取元素,可使用 find 运算。
  • set 不支持STL里的reverse和sort算法。

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值