C++/C++11中std::set用法汇总

一个容器就是一些特定类型对象的集合。顺序容器(sequential container)为程序员提供了控制元素存储和访问顺序的能力。这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应。与之相对的,有序和无序关联容器,则根据关键字的值来存储元素。

标准库还提供了三种容器适配器,分别为容器操作定义了不同的接口,来与容器类型适配:stack、queue和priority_queue。适配器(adaptor)是标准库中的一个通用概念。容器、迭代器和函数都有适配器。本质上,一个适配器是一种机制,能使某种事物的行为看起来像另外一种事物一样。一个容器适配器接受一种已有的容器类型,使其行为看起来像一种不同的类型。

顺序容器包括vector、deque、list、forward_list、array、string,所有顺序容器都提供了快速顺序访问元素的能力。

关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的。与之相对,顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。

类似顺序容器,关联容器也是模板。

关联容器不支持顺序容器的位置相关的操作。原因是关联容器中元素是根据关键字存储的,这些操作对关联容器没有意义。而且,关联容器也不支持构造函数或插入操作这些接受一个元素值和一个数量值得操作。

关联容器支持高效的关键字查找和访问。两个主要的关联容器(associative container)类型是map和set。map中的元素是一些关键字----值(key--value)对:关键字起到索引的作用,值则表示与索引相关联的数据。set中每个元素只包含一个关键字:set支持高效的关键字查询操作----检查一个给定关键字是否在set中。

标准库提供8个关联容器:

(1)、按关键字有序保存元素:map(关联数组:保存关键字----值对);set(关键字即值,即只保存关键字的容器);multimap(关键字可重复出现的map);multiset(关键字可重复出现的set);

(2)、无序集合:unordered_map(用哈希函数组织的map);unordered_set(用哈希函数组织的set);unordered_multimap(哈希组织的map,关键字可以重复出现);unordered_multiset(哈希组织的sest,关键字可以重复出现)。

map是关键字----值对的集合,与之相对,set就是关键字的简单集合。当只是想知道一个值是否存在时,set是最有用的。

在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。Set中元素的值不能直接被改变。set内部采用的是一种非常高效的平衡检索二叉树:红黑树,也称为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树。

下面是从cplusplus和cppreference网站摘录的测试代码:
--------------------- 
作者:fengbingchun 
来源:CSDN 
原文:https://blog.csdn.net/fengbingchun/article/details/63268962 
版权声明:本文为博主原创文章,转载请附上博文链接!

#include "set.hpp"
#include <set>
#include <iostream>
#include <string>
#include <cassert>
#include <chrono>
#include <functional>
#include <iomanip>
 
// reference: http://www.cplusplus.com/reference/set/set/
static bool fncomp(int lhs, int rhs) { return lhs<rhs; }
 
struct classcomp {
	bool operator() (const int& lhs, const int& rhs) const
	{
		return lhs<rhs;
	}
};
 
int test_set_cplusplus()
{
{ // set:构造函数
	std::set<int> first;                           // empty set of ints
 
	int myints[] = { 10, 20, 30, 40, 50 };
	std::set<int> second(myints, myints + 5);        // range
 
	std::set<int> third(second);                  // a copy of second
 
	std::set<int> fourth(second.begin(), second.end());  // iterator ctor.
 
	std::set<int, classcomp> fifth;                 // class as Compare
 
	bool(*fn_pt)(int, int) = fncomp;
	std::set<int, bool(*)(int, int)> sixth(fn_pt);  // function pointer as Compare
}
 
{ // 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';
}
 
{ // clear:清除所有元素
	std::set<int> myset;
 
	myset.insert(100);
	myset.insert(200);
	myset.insert(300);
 
	std::cout << "myset contains:";
	for (std::set<int>::iterator it = myset.begin(); it != myset.end(); ++it)
		std::cout << ' ' << *it;
	std::cout << '\n';
 
	myset.clear();
	myset.insert(1101);
	myset.insert(2202);
 
	std::cout << "myset contains:";
	for (std::set<int>::iterator it = myset.begin(); it != myset.end(); ++it)
		std::cout << ' ' << *it;
	std::cout << '\n';
}
 
{ // count:判断某一个关键字是否在set内,返回0或者1
	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";
	}
 
}
 
{ // cbegin/cend(c++11): Returns a const_iterator pointing to the first element in the container/
	// Returns a const_iterator pointing to the past-the-end element in the container
	std::set<int> myset = { 50, 20, 60, 10, 25 };
 
	std::cout << "myset contains:";
	for (auto it = myset.cbegin(); it != myset.cend(); ++it)
		std::cout << ' ' << *it;
 
	std::cout << '\n';
}
 
{ // crbegin/crend(c++11):Return const_reverse_iterator to reverse beginning/
	// Return const_reverse_iterator to reverse end
	std::set<int> myset = { 50, 20, 60, 10, 25 };
 
	std::cout << "myset backwards:";
	for (auto rit = myset.crbegin(); rit != myset.crend(); ++rit)
		std::cout << ' ' << *rit;
 
	std::cout << '\n';
}
 
{ // emplace(c++11):如果新元素的值是唯一的,将插入该元素
	std::set<std::string> myset;
 
	myset.emplace("foo");
	myset.emplace("bar");
	auto ret = myset.emplace("foo");
 
	if (!ret.second) std::cout << "foo already exists in myset\n";
}
 
{ // emplace_hint(c++11):Construct and insert element with hint
	std::set<std::string> myset;
	auto it = myset.cbegin();
 
	myset.emplace_hint(it, "alpha");
	it = myset.emplace_hint(myset.cend(), "omega");
	it = myset.emplace_hint(it, "epsilon");
	it = myset.emplace_hint(it, "beta");
 
	std::cout << "myset contains:";
	for (const std::string& x : myset)
		std::cout << ' ' << x;
	std::cout << '\n';
}
 
{ // empty:如果集合为空,返回true
	std::set<int> myset;
 
	myset.insert(20);
	myset.insert(30);
	myset.insert(10);
 
	std::cout << "myset contains:";
	while (!myset.empty()) {
		std::cout << ' ' << *myset.begin();
		myset.erase(myset.begin());
	}
	std::cout << '\n';
}
 
{ // 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';
}
 
{ // 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';
}
 
{ // find:返回一个指向被查找到元素的迭代器,如果没找到则返回end()
	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';
}
 
{ // get_allocator:返回集合set的分配器
	std::set<int> myset;
	int * p;
	unsigned int i;
 
	// allocate an array of 5 elements using myset's allocator:
	p = myset.get_allocator().allocate(5);
 
	// assign some values to array
	for (i = 0; i<5; i++) p[i] = (i + 1) * 10;
 
	std::cout << "The allocated array contains:";
	for (i = 0; i<5; i++) std::cout << ' ' << p[i];
	std::cout << '\n';
 
	myset.get_allocator().deallocate(p, 5);
}
 
{ // 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';
}
 
{ // key_comp:Returns a copy of the comparison object used by the container
	std::set<int> myset;
	int highest;
 
	std::set<int>::key_compare mycomp = myset.key_comp();
 
	for (int i = 0; i <= 5; i++) myset.insert(i);
 
	std::cout << "myset contains:";
 
	highest = *myset.rbegin();
	std::set<int>::iterator it = myset.begin();
	do {
		std::cout << ' ' << *it;
	} while (mycomp(*(++it), highest));
 
	std::cout << '\n';
}
 
{ // lower_bond:返回指向大于(或等于)某值的第一个元素的迭代器
	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';
}
 
{ // max_size:返回集合能容纳的元素的最大限值
	int i;
	std::set<int> myset;
 
	if (myset.max_size() > 1000) {
		for (i = 0; i<1000; i++) myset.insert(i);
		std::cout << "The set contains 1000 elements.\n";
	} else
		std::cout << "The set could not hold 1000 elements.\n";
}
 
{ // operator =:Assigns new contents to the container, replacing its current content
	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';
}
 
{ // 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';
}
 
{ // 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';
}
 
{ // 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';
}
 
{ // 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';
}
 
{ // value_comp:Returns a copy of the comparison object used by the container
	std::set<int> myset;
 
	std::set<int>::value_compare mycomp = myset.value_comp();
 
	for (int i = 0; i <= 5; i++) myset.insert(i);
 
	std::cout << "myset contains:";
 
	int highest = *myset.rbegin();
	std::set<int>::iterator it = myset.begin();
	do {
		std::cout << ' ' << *it;
	} while (mycomp(*(++it), highest));
 
	std::cout << '\n';
}
 
{ // relational operators:==/!=/</<=/>/>=
	std::set<int> foo, bar;
	foo.insert(10);
	bar.insert(20);
	bar.insert(30);
	foo.insert(40);
 
	// foo ({10,40}) vs bar ({20,30}):
	if (foo == bar) std::cout << "foo and bar are equal\n";
	if (foo != bar) std::cout << "foo and bar are not equal\n";
	if (foo< bar) std::cout << "foo is less than bar\n";
	if (foo> bar) std::cout << "foo is greater than bar\n";
	if (foo <= bar) std::cout << "foo is less than or equal to bar\n";
	if (foo >= bar) std::cout << "foo is greater than or equal to bar\n";
}
 
	return 0;
}
 
// reference: http://en.cppreference.com/w/cpp/container/set
struct Point { double x, y; };
struct PointCmp {
	bool operator()(const Point& lhs, const Point& rhs) const {
		return std::hypot(lhs.x, lhs.y) < std::hypot(rhs.x, rhs.y);
	}
};
 
static void display_sizes(const std::set<int> &nums1, const std::set<int> &nums2, const std::set<int> &nums3)
{
	std::cout << "nums1: " << nums1.size()
		<< " nums2: " << nums2.size()
		<< " nums3: " << nums3.size() << '\n';
}
 
class Dew
{
private:
	int a;
	int b;
	int c;
 
public:
	Dew(int _a, int _b, int _c)
		: a(_a), b(_b), c(_c)
	{}
 
	bool operator<(const Dew &other) const
	{
		if (a < other.a)
			return true;
		if (a == other.a && b < other.b)
			return true;
		return (a == other.a && b == other.b && c < other.c);
	}
};
 
const int nof_operations = 120;
 
int set_emplace() {
	std::set<Dew> set;
	for (int i = 0; i < nof_operations; ++i)
	for (int j = 0; j < nof_operations; ++j)
	for (int k = 0; k < nof_operations; ++k)
		set.emplace(i, j, k);
 
	return set.size();
}
 
int set_insert() {
	std::set<Dew> set;
	for (int i = 0; i < nof_operations; ++i)
	for (int j = 0; j < nof_operations; ++j)
	for (int k = 0; k < nof_operations; ++k)
		set.insert(Dew(i, j, k));
 
	return set.size();
}
 
void timeit(std::function<int()> set_test, std::string what = "") {
	auto start = std::chrono::system_clock::now();
	int setsize = set_test();
	auto stop = std::chrono::system_clock::now();
	std::chrono::duration<double, std::milli> time = stop - start;
	if (what.size() > 0 && setsize > 0) {
		std::cout << std::fixed << std::setprecision(2)
			<< time.count() << "  ms for " << what << '\n';
	}
}
 
int test_set_cppreference()
{
{ // constructor: constructs the set 
	// (1) Default constructor
	std::set<std::string> a;
	a.insert("cat");
	a.insert("dog");
	a.insert("horse");
	for (auto& str : a) std::cout << str << ' ';
	std::cout << '\n';
 
	// (2) Iterator constructor
	std::set<std::string> b(a.find("dog"), a.end());
	for (auto& str : b) std::cout << str << ' ';
	std::cout << '\n';
 
	// (3) Copy constructor
	std::set<std::string> c(a);
	c.insert("another horse");
	for (auto& str : c) std::cout << str << ' ';
	std::cout << '\n';
 
	// (4) Move constructor
	std::set<std::string> d(std::move(a));
	for (auto& str : d) std::cout << str << ' ';
	std::cout << '\n';
	std::cout << "moved-from set is ";
	for (auto& str : a) std::cout << str << ' ';
	std::cout << '\n';
 
	// (5) Initializer list constructor
	std::set<std::string> e{ "one", "two", "three", "five", "eight" };
	for (auto& str : e) std::cout << str << ' ';
	std::cout << '\n';
 
	// custom comparison
	std::set<Point, PointCmp> z = { { 2, 5 }, { 3, 4 }, { 1, 1 } };
	z.insert({ 1, -1 }); // this fails because the magnitude of 1,-1 equals 1,1
	for (auto& p : z) std::cout << '(' << p.x << ',' << p.y << ") ";
	std::cout << '\n';
}
 
{ // operator = : assigns values to the container 
	std::set<int> nums1{ 3, 1, 4, 6, 5, 9 };
	std::set<int> nums2;
	std::set<int> nums3;
 
	std::cout << "Initially:\n";
	display_sizes(nums1, nums2, nums3);
 
	// copy assignment copies data from nums1 to nums2
	nums2 = nums1;
 
	std::cout << "After assigment:\n";
	display_sizes(nums1, nums2, nums3);
 
	// move assignment moves data from nums1 to nums3,
	// modifying both nums1 and nums3
	nums3 = std::move(nums1);
 
	std::cout << "After move assigment:\n";
	display_sizes(nums1, nums2, nums3);
}
 
{ // get_allocator: returns the associated allocator 
}
 
{ // begin/end(cbegin/cend): returns an iterator to the beginning /returns an iterator to the end
	std::set<int> set = { 6, 1, 3, 4, 2, 5 };
	for (auto it = set.begin(); it != set.end(); ++it)
		std::cout << *it << "\n";
}
 
{ // rbegin/rend(crbegin/crend): returns a reverse iterator to the beginning /returns a reverse iterator to the end 
}
 
{ // empty: checks whether the container is empty 
	std::set<int> numbers;
	std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';
 
	numbers.insert(42);
	numbers.insert(13317);
	std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}
 
{ // size: returns the number of elements 
	std::set<int> nums{ 1, 3, 5, 7 };
 
	std::cout << "nums contains " << nums.size() << " elements.\n";
}
 
{ // max_size: returns the maximum possible number of elements 
	std::set<char> s;
	std::cout << "Maximum size of a 'set' is " << s.max_size() << "\n";
}
 
{ // clear: clears the contents 
}
 
{ // insert: inserts elements
	std::set<int> set;
 
	auto result_1 = set.insert(3);
	assert(result_1.first != set.end()); // it's a valid iterator
	assert(*result_1.first == 3);
	if (result_1.second)
		std::cout << "insert done\n";
 
	auto result_2 = set.insert(3);
	assert(result_2.first == result_1.first); // same iterator
	assert(*result_2.first == 3);
	if (!result_2.second)
		std::cout << "no insertion\n";
}
 
{ // emplace(c++11): constructs element in-place 
	set_insert();
	timeit(set_insert, "insert");
	timeit(set_emplace, "emplace");
	timeit(set_insert, "insert");
	timeit(set_emplace, "emplace");
}
 
{ // emplace_hint(c++11): constructs elements in-place using a hint 
	// reference: http://en.cppreference.com/w/cpp/container/set/emplace_hint
}
 
{ // erase: erases elements 
	std::set<int> c = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	// erase all odd numbers from c
	for (auto it = c.begin(); it != c.end();)
	if (*it % 2 == 1)
		it = c.erase(it);
	else
		++it;
	for (int n : c)
		std::cout << n << ' ';
}
 
{ // swap: swaps the contents 
}
 
{ // count: returns the number of elements matching specific key 
}
 
{ // find: finds element with specific key 
	std::set<int> example = { 1, 2, 3, 4 };
 
	auto search = example.find(2);
	if (search != example.end()) {
		std::cout << "Found " << (*search) << '\n';
	}
	else {
		std::cout << "Not found\n";
	}
}
 
{ // equal_range: returns range of elements matching a specific key 
}
 
{ // lower_bound: returns an iterator to the first element not less than the given key 
}
 
{ // upper_bound: returns an iterator to the first element greater than the given key 
}
 
{ // key_comp: returns the function that compares keys 
}
 
{ // value_comp: returns the function that compares keys in objects of type value_type
}
 
	return 0;
}

 

  • 10
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值