码迷,mamicode.com
首页 > 其他好文 > 详细

STL 之 set 使用详解

时间:2015-04-15 21:35:17      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:


使用setmultiset前包含头文件<set>

setmultiset都是集合类,差别在与set中不允许有重复元素,multiset中允许有重复元素。他们都是有序集合。

std::set is an associative container(关联容器) that contains a sorted set of unique objects of type Key. Sorting is done using the key comparison function Compare. Search, removal, and insertion operations have logarithmic complexity. Sets are usually implemented as red-black trees.

Member types(成员类型)

技术分享

Member functions(成员函数)

构造函数

构造函数有如下这多:

技术分享

下面的举例是常用的构造方式,从下面的代码中我们很容易掌握常用的构造方法。

#include "stdafx.h"
#include <iostream>
#include <string>
#include <set>

// Helper function for printing pairs.
template<class Ch, class Tr, class A, class B> inline
std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& stream, std::pair<A, B> p)
{
    return stream << ‘(‘ << p.first << ", " << p.second << ‘)‘;
}

// Helper function for printing containers.
template<class Ch, class Tr, class Co>
std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& stream, Co& c)
{
    stream << ‘{‘ << *c.begin();

    for (auto it = ++(c.begin()); it != c.end(); ++it)
        stream << ", " << *it;

    stream << ‘}‘ << std::endl;
    return stream;
}

int main()
{
    // (1) Default constructor
    std::set<std::string> a; //empty set
    a.insert("something");
    a.insert("anything");
    a.insert("that thing");
    std::cout << "a = " << a; // sorted

    // (2) Iterator constructor
    std::set<std::string> b(a.find("anything"), a.end()); // find() return iterator
    std::cout << std::string(80, ‘-‘) << std::endl;
    std::cout << "b = " << b; // a == b

    // (3) Copy constructor
    std::set<std::string> c(a);
    c.insert("another thing"); // insert and sorted
    std::cout << std::string(80, ‘-‘) << std::endl;
    std::cout << "a = " << a; 
    std::cout << "c = " << c;

    // (4) Move constructor
    std::set<std::string> d(std::move(a)); // ok.ok.ok --- a to be empty
    std::cout << std::string(80, ‘-‘) << std::endl;
    std::cout << "a = nullptr" << std::endl;
    std::cout << "d = " << d;

    // (5) Initializer list constructor
    std::set<std::string> e{
        "one", "two", "three", "five", "eight"
    };
    std::cout << std::string(80, ‘-‘) << std::endl;
    std::cout << "e = " << e;
}

输出:

a = {anything, something, that thing}
--------------------------------------------------------------------------------
b = {anything, something, that thing}
--------------------------------------------------------------------------------
a = {anything, something, that thing}
c = {another thing, anything, something, that thing}
--------------------------------------------------------------------------------
a = nullptr
d = {anything, something, that thing}
--------------------------------------------------------------------------------
e = {eight, five, one, three, two}

析构函数

~set();

Destructs the container. The destructors of the elements are called and the used storage is deallocated. Note, that if the elements are pointers, the pointed-to objects are not destroyed.

析构函数会完成两个任务:1)调用set中每个元素的析构函数,2)释放元素占用的空间
如果存储的元素值指针,那么指针指向的对象并不会释放,容易造成内存泄露。

operator=

技术分享

示例代码如下:

#include <set>
#include <iostream>

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‘;
}

int main()
{
    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); // move 将nums1对内存的所有权剥夺,通过调用上述的(2)赋值方式将内存所有权转交给nums3

    std::cout << "After move assigment:\n"; 
    display_sizes(nums1, nums2, nums3);
}

输出:

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

get_allocator

allocator_type get_allocator() const;

Returns the allocator associated with the container.

Iterators

begin & cbegin

c 表示 const

iterator begin();
const_iterator begin() const;
const_iterator cbegin() const; (since C++11)

技术分享

end & cend

iterator end();
const_iterator end() const;
const_iterator cend() const; (since C++11)

rbegin & crbegin

r 表示 reverse

reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
const_reverse_iterator crbegin() const; (since C++11)

技术分享

Returns a reverse iterator to the first element of the reversed container. It corresponds to the last element of the non-reversed container.

rend & crend

reverse_iterator rend();
const_reverse_iterator rend() const;
const_reverse_iterator crend() const; (since C++11)

Capacity

empty

bool empty() const;

Checks if the container has no elements, i.e. whether begin() == end().

size

size_type size() const;

Returns the number of elements in the container, i.e. std::distance(begin(), end()).

max_size

size_type max_size() const;

Returns the maximum number of elements the container is able to hold due to system or library implementation limitations,

返回的是当前容器在内存中所能分配的最大元素值-通常是一个较大的值,max_size() - size()表示还能分配的元素个数。跟内存重新分配没有关系,只与系统和库实现相关。

#include <iostream>
#include <set>

int main()
{
    std::set<char> s;
    std::cout << "Maximum size of a ‘set‘ is " << s.max_size() << "\n";
}

输出:

Maximum size of a ‘set‘ is 18446744073709551615

Modifiers

clear

void clear();

Removes all elements from the container.

insert

技术分享

说明:

1-2) 插入一个值,返回的是pair, pair->first指向插入值的迭代器, pair->second返回是否插入成功,在下面的例子中很清楚。

3-4) 在指定位置插入指定值。

5)插入一个范围内的元素。

6)插入一个初始化列表,没什么意思。

#include <set>
#include <cassert>
#include <iostream>

int main()
{
  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) // 没有插入成功, 返回false
    std::cout << "no insertion\n";
}

输出:

insert done
no insertion

emplace

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args ); (since C++11)

Inserts a new element into the container by constructing it in-place with the given args if there is no element with the key in the container.

Careful use of emplace allows the new element to be constructed while avoiding unnecessary copy or move operations

emplace_hint

#include <set>
#include <chrono>
#include <iostream>
#include <iomanip>
#include <functional>

const int nof_operations = 100500;

int set_emplace() {
  std::set<int> set;
  for(int i = 0; i < nof_operations; ++i) {
    set.emplace(i);
  }
  return set.size();
}

int set_emplace_hint() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = 0; i < nof_operations; ++i) {
    set.emplace_hint(it, i);
    it = set.end();
  }
  return set.size();
}

int set_emplace_hint_wrong() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = nof_operations; i > 0; --i) {
    set.emplace_hint(it, i);
    it = set.end();
  }
  return set.size();
}

int set_emplace_hint_corrected() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = nof_operations; i > 0; --i) {
    set.emplace_hint(it, i);
    it = set.begin();
  }
  return set.size();
}

int set_emplace_hint_closest() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = 0; i < nof_operations; ++i) {
    it = set.emplace_hint(it, i);
  }
  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 main() {
   timeit(set_emplace); // stack warmup
   timeit(set_emplace, "plain emplace");
   timeit(set_emplace_hint, "emplace with correct hint");
   timeit(set_emplace_hint_wrong, "emplace with wrong hint");
   timeit(set_emplace_hint_corrected, "corrected emplace");
   timeit(set_emplace_hint_closest, "emplace using returned iterator");
}

输出:

18.96  ms for plain emplace
7.95  ms for emplace with correct hint
19.39  ms for emplace with wrong hint
8.39  ms for corrected emplace
7.90  ms for emplace using returned iterator

erase

技术分享

1) 移除指定位置的元素,返回的迭代器指向后一个元素

2)移除指定范围的元素

3)移除指定值

swap

void swap( set& other );

Exchanges the contents of the container with those of other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid

Lookup

count

size_type count( const Key& key ) const;  (1)   
template< class K > 
size_type count( const K& x ) const; (2)    (since C++14)

1) 返回指定元素值的个数,只可能返回0或者1.因为不允许重复元素的存在.

2) Returns the number of elements with key that compares equivalent to the value x. This overload only participates in overload resolution if the qualified-id Compare::is_transparent is valid and denotes a type. They allow calling this function without constructing an instance of Key.

find

技术分享

返回指向指定元素的迭代器,如果没有找到指定元素,那么返回尾后迭代器。将返回的迭代器和end()比较是否相等可以判断是否找到指定元素。

#include <iostream>
#include <set>

int main()
{  
    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";
    }
}

输出:

Found 2

equal_range

std::pair<iterator,iterator> equal_range( const Key& key );
template< class K >
std::pair<iterator,iterator> equal_range( const K& x );

因为在集合中相等的元素连续存储,因此可以使用一个范围表示等于指定值的范围。

第一个迭代器指向不小于指定值的位置,第二个迭代器指向第一个大于指定值的位置。也就是[first,second)。这两个迭代器也是lower_boundupper_bound返回的迭代器指向的位置。

lower_bound

iterator lower_bound( const Key& key );  (1)    
const_iterator lower_bound( const Key& key ) const; (1) 
template< class K > 
iterator lower_bound(const K& x); (2)   (since C++14)
template< class K > 
const_iterator lower_bound(const K& x) const; (2)   (since C++14)

返回的迭代器指向不小于指定值的元素。

upper_bound

iterator upper_bound( const Key& key ); (1) 
const_iterator upper_bound( const Key& key ) const; (1) 
template< class K > 
iterator upper_bound( const K& x ); (2) (since C++14)
template< class K > 
const_iterator upper_bound( const K& x ) const; (2) (since C++14)

返回的迭代器指向第一个大于指定值的元素。

Observers

key_comp

key_compare key_comp() const;

Returns the function object that compares the keys, which is a copy of this container’s
constructor argument comp. It is the same as value_comp.

value_comp

std::set::value_compare value_comp() const;

Returns the function object that compares the values. It is the same as key_comp.

Non-member functions

operator==,!=,<,<=,>,>=(std::set)

两个容器大小相同并且相同位置的值对应相等,那么返回true

swap

template< class Key, class Compare, class Alloc >
void swap( set<Key,Compare,Alloc>& lhs, set<Key,Compare,Alloc>& rhs );

Specializes the std::swap algorithm for std::set. Swaps the contents of lhs and rhs. Calls lhs.swap(rhs).

STL 之 set 使用详解

标签:

原文地址:http://blog.csdn.net/yapian8/article/details/45064061

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!