您的位置:首页 > 编程语言 > C语言/C++

C++——std::Set

2018-01-05 15:18 225 查看

写在前面:

在写这篇博客之前吐个槽,其实也可不不用这么麻烦这么写博客。讲道理其实在书本上学这些知识应该挺快的。可以书上看一遍记个大概,然后做题的过程中,不断遇见各种小知识,这样分散的积累,然后一定规模后,就可以系统的整理。但是现在先花时间来做这件事,其实也可以,建立主体的框架,后面再慢慢细化丰富。也没必要想那么多,慢慢来。不管方法是什么,重要的是每天要做点事。那么这篇博客学习set容器。目前学习了vector、map容器,都是“浮于表面“地学习容器创建、函数等。没有细究容器实现原理。这里也是提一下这个问题,后面还是有必要仔细学习容器的基本原理。

set类与头文件包含:

STL set容器微软官方译为”集合“。STL 容器类集用于存储和检索集合中的数据,此集合中包含的元素值是唯一的,并且用作数据自动排序所依据的键值。 不能直接更改集中元素的值。 必须先删除旧值,才能插入具有新值的元素。

set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与有字数的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。

平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。

构造set集合的主要目的是为了快速检索,使用set前,需要在程序头文件中包含声明“#include”。

#include <set> //注意,STL头文件没有扩展名.h


set语法表达如下:

template <
class Key,
class Traits=less<Key>,
class Allocator=allocator<Key> >
class set


Key::要存储在集中的元素数据类型。

Traits:一种提供函数对象的类型,该函数对象将两个元素值作为排序键进行比较,以确定其在集中的相对顺序。 此参数是可选的为二元谓词较少 * <> > *是默认值。

Allocator:一种表示存储的分配器对象的类型,该分配器
4000
对象封装有关集的内存分配和解除分配的详细信息。 此参数是可选的而默认值是分配器<> >。

set::set

这次就不想之前那样分开写了。直接在程序中添加必要注释。

using namespace std;

// 创建一个空set。元素类型为int
set <int> s0;

// 创建一个set,并指定元素比较方式,less<int> ,然后插入4个元素
set <int, less<int> > s1;
s1.insert(10);
s1.insert(20);
s1.insert(30);
s1.insert(40);

// 创建一个set,并指定元素比较方式,less<int> ,然后插入2个元素
set <int, less<int> > s2;
s2.insert(10);
s2.insert(20);

// 创建一个set,使用s1的分配器。
set <int>::allocator_type s1_Alloc; //创建一个分配器
s1_Alloc = s1.get_allocator();  //获取s1的分配器
set <int> s3(less<int>(), s1_Alloc);
s3.insert(30);

// 通过拷贝一个set的方法创建一个set
set <int> s4(s1);

// 通过拷贝[first,last]的部分创建一个set
set <int>::const_iterator s1_bcIter, s1_ecIter;
s1_bcIter = s1.begin();
s1_ecIter = s1.begin();
s1_ecIter++;
s1_ecIter++;
set <int> s5(s1_bcIter, s1_ecIter);

// 结合部分拷贝与分配器的方式创建一个set
set <int>::allocator_type s2_Alloc;
s2_Alloc = s2.get_allocator();
set <int> s6(s4.begin(), ++s4.begin(), less<int>(), s2_Alloc);

// 通过移动s5创建s7.s5为空。s7为新的s5
set<int> s7(move(s5));
cout << "s7 =";
for (auto i : s7)
cout << " " << i;
cout << endl;

// 通过一个初始列表创建set
cout << "s8 =";
set<int> s8{ { 1, 2, 3, 4 } };

set<int> s9{ { 5, 6, 7, 8 }, less<int>() };
set<int> s10{ { 10, 20, 30, 40 }, less<int>(), s9.get_allocator() };


set:: operator =

将此元素替换为set使用从另一个元素set。

int myints[]={ 12,82,37,64,15 };
std::set<int> first (myints,myints+5);   // set with 5 ints
std::set<int> second;                    // empty set

second = first;                          // now second contains the 5 ints
first = std::set<int>();                 // and first is empty

std::cout << "Size of first: " << int (first.size()) << '\n';
std::cout << "Size of second: " << int (second.size()) << '\n';
//Output:
//Size of first: 0   //说明first现在为空
//Size of second: 5   //说明second是first的拷贝。


set-iterators:

迭代器与vector、map相同。



这里补充一下通过迭代器begin()与end()进行容器的遍历:

int myints[] = {75,23,65,42,13};
std::set<int> myset (myints,myints+5);

std::cout << "myset contains:";
for (std::set<int>::iterator it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;

std::cout << '\n';
//Output:myset contains: 13 23 42 65 75


也可以通过反向迭代器rbegin()与rend()进行容器的遍历:

int myints[] = {21,64,17,78,49};
std::set<int> myset (myints,myints+5);

std::set<int>::reverse_iterator rit;

std::cout << "myset contains:";
for (rit=myset.rbegin(); rit != myset.rend(); ++rit)
std::cout << ' ' << *rit;

std::cout << '\n';
//Output:myset contains: 78 64 49 21 17


set-capaticy



1.set::empty:测试集合是否为空。返回值中true如果该集为空,则为false如果该集为空。

2.set::size:返回集合当前所含元素个数。

std::set<int> myints;
std::cout << "0. size: " << myints.size() << '\n';

for (int i=0; i<10; ++i) myints.insert(i);
std::cout << "1. size: " << myints.size() << '\n';

myints.insert (100);
std::cout << "2. size: " << myints.size() << '\n';

myints.erase(5);
std::cout << "3. size: " << myints.size() << '\n';

//output
//0. size: 0
//1. size: 10
//2. size: 11
//3. size: 10


3.set::max_size:返回集合的最大长度。

set-modifiers:



1.set::insert:将一个元素或元素范围插入到集合。

std::set<int> myset;
std::set<int>::iterator it;
std::pair<std::set<int>::iterator,bool> ret;

// set some initial values:
for (int i=1; i<=5; ++i) myset.insert(i*10);    // set: 10 20 30 40 50

ret = myset.insert(20);               // no new element inserted

if (ret.second==false) it=ret.first;  // "it" now points to element 20

myset.insert (it,25);                 // max efficiency inserting
myset.insert (it,24);                 // max efficiency inserting
myset.insert (it,26);                 // no max efficiency inserting

int myints[]= {5,10,15};              // 10 already in set, not inserted
myset.insert (myints,myints+3);

std::cout << "myset contains:";
for (it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

//Output:
//myset contains: 5 10 15 20 24 25 26 30 40 50


2.set::erase:从集中的指定位置移除一个元素或元素范围,或者移除与指定键匹配的元素。

std::set<int> myset;
std::set<int>::iterator it;

// insert some values:
for (int i=1; i<10; i++) myset.insert(i*10);  // 10 20 30 40 50 60 70 80 90

it = myset.begin();
++it;                                         // "it" points now to 20

myset.erase (it);
myset.erase (40);

it = myset.find (60);
myset.erase (it, myset.end());

std::cout << "myset contains:";
for (it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

//Output:
//myset contains: 10 30 50


3.set::swap:交换两个集的元素。

int myints[]={12,75,10,32,20,25};
std::set<int> first (myints,myints+3);     // 10,12,75
std::set<int> second (myints+3,myints+6);  // 20,25,32

first.swap(second);

std::cout << "first contains:";
for (std::set<int>::iterator it=first.begin(); it!=first.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

std::cout << "second contains:";
for (std::set<int>::iterator it=second.begin(); it!=second.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

//Output:
//first contains: 20 25 32
//second contains: 10 12 75


4.set::clear:清除集的所有元素。

set-observers:



set-operations:



1.set::find:返回引用集中具有与指定键等效的键的元素的位置的迭代器。返回值是一个迭代器。

std::set<int> myset;
std::set<int>::iterator it;

// set some initial values:
for (int i=1; i<=5; i++) myset.insert(i*10);    // set: 10 20 30 40 50

it=myset.find(20);
myset.erase (it);
myset.erase (myset.find(40));

std::cout << "myset contains:";
for (it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

//Output:
//myset contains: 10 30 50


2.set::count:返回集中其键与指定为参数的键匹配的元素数量。

std::set<int> myset;

// set some initial values:
for (int i=1; i<5; ++i) myset.insert(i*3);    // set: 3 6 9 12

for (int i=0; i<10; ++i)
{
std::cout << i;
if (myset.count(i)!=0)
std::cout << " is an element of myset.\n";
else
std::cout << " is not an element of myset.\n";
}

//Output:
//0 is not an element of myset.
//1 is not an element of myset.
//2 is not an element of myset.
//3 is an element of myset.
//4 is not an element of myset.
//5 is not an element of myset.
//6 is an element of myset.
//7 is not an element of myset.
//8 is not an element of myset.
//9 is an element of myset.


3.set:: lower_bound:返回一个迭代器,此迭代器指向集中其键等于或大于指定键的第一个元素。其键等于或大于指定参数键或如果未在集中最后一个元素之后的位置,它解决匹配集中的元素的位置找到的键。

4.set:: upper_bound:返回一个迭代器的第一个元素中一组,其键大于指定键。其键大于指定参数键,或如果未在集中最后一个元素之后的位置,它解决匹配集中的元素的位置找到的键。

std::set<int> myset;
std::set<int>::iterator itlow,itup;

for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90

itlow=myset.lower_bound (30);                //        ^
itup=myset.upper_bound (60);                 //                ^

myset.erase(itlow,itup);                     // 10 20 70 80 90

std::cout << "myset contains:";
for (std::set<int>::iterator it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';


5.set::equal_range:返回一对迭代器分别给一组中的第一个元素大于或等于指定的键的第一个元素以及集中其键大于指定键的键。

std::set<int> myset;

for (int i=1; i<=5; i++) myset.insert(i*10);   // myset: 10 20 30 40 50

std::pair<std::set<int>::const_iterator,std::set<int>::const_iterator> ret;
ret = myset.equal_range(30);

std::cout << "the lower bound points to: " << *ret.first << '\n';
std::cout << "the upper bound points to: " << *ret.second << '\n';
//output:
//the lower bound points to: 30
//the upper bound points to: 40


写在最后:

简要整理了一下set。对set有了一个初步的认识,它简单来说就是一个集合。一个不允许元素重复,并且可以自动排序的集合。虽然还是很基础,但是不断慢慢积累。巨大的知识体量,慢慢蚕食也许是个不错的选择。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: