1. 简介
容器set 和multiset 让程序员能够在容器中快速查找键,键是存储在一维容器中的值 set 和multiset之间的区别在于,后者可存储重复的值,而前者只能存储唯一的值 为实现快速搜索,set 和multiset 的内部结构像二叉树,这意味着将元素插入到set 或multiset时将对其进行排序,以提高查找速度 (插入时对元素进行排序,默认升序排列) 位于set 中特定位置的元素不能替换为值不同的新元素,这是因为set 将把新元素同内部树中的其他元素进行比较,进而将其放在其他位置
2. STL set 和multiset 的基本操作
2.1 实例化std::set 对象
# include <iostream>
# include <set>
template < typename T >
struct SortDescending {
bool operator ( ) ( const T& lhs, const T& rhs) const {
return ( lhs > rhs) ;
}
} ;
int main ( ) {
using namespace std;
set< int > setInts1;
multiset< int > msetInts1;
set< int , SortDescending< int > > setInts2;
multiset< int , SortDescending< int > > msetInts2;
set< int > setInts3 ( setInts1) ;
multiset< int > msetInts3 ( setInts1. cbegin ( ) , setInts1. cend ( ) ) ;
return 0 ;
}
2.2 在set 或multiset 中插入元素
要在这两种容器中插入元素,都可使用成员函数insert(),这个函数接受要插入的值或容器的指定范围 mulitset::count()确定multiset 包含多少个这样的元素
setInts. insert ( - 1 ) ;
msetInts. insert ( setInts. begin ( ) , setInts. end ( ) ) ;
2.3 在STL set 或multiset 中查找元素
auto elementFound = setInts. find ( - 1 ) ;
if ( elementFound != setInts. end ( ) ) {
cout << "Element " << * elementFound << " found!" << endl;
} else {
cout << "Element not found in set!" << endl;
}
2.4 删除STL set 或multiset 中的元素
# include <set>
# include <iostream>
using namespace std;
template < typename T >
void DisplayContents ( const T& Input) {
for ( auto element = Input. cbegin ( ) ; element != Input. cend ( ) ; ++ element) {
cout << * element << ' ' ;
}
cout << endl;
}
typedef multiset< int > MSETINT;
int main ( ) {
MSETINT msetInts{ 43 , 78 , 78 , - 1 , 124 } ;
cout << "multiset contains " << msetInts. size ( ) << " elements: " ;
DisplayContents ( msetInts) ;
cout << "Enter a number to erase from the set: " ;
int input = 0 ;
cin >> input;
cout << "Erasing " << msetInts. count ( input) ;
cout << " instances of value " << input << endl;
msetInts. erase ( input) ;
cout << "multiset now contains " << msetInts. size ( ) << " elements: " ;
DisplayContents ( msetInts) ;
return 0 ;
}
2.5 使用set 容器的实际应用
基于菜单的电话簿的简单实现,它让用户能够插入、查找、删除和显示人名和电话号码 std::set 排序是在插入元素时进行的
# include <set>
# include <iostream>
# include <string>
using namespace std;
template < typename T >
void DisplayContents ( const T& container) {
for ( auto iElement = container. cbegin ( ) ;
iElement != container. cend ( ) ;
++ iElement) {
cout << * iElement << endl;
}
cout << endl;
}
struct ContactItem
{
string name;
string phoneNum;
string displayAs;
ContactItem ( const string& nameInit, const string& phone) {
this -> name = nameInit;
this -> phoneNum = phone;
this -> displayAs = ( name + ": " + phoneNum) ;
}
bool operator == ( const ContactItem& itemToCompare) const {
return ( this -> name < itemToCompare. name) ;
}
bool operator < ( const ContactItem& itemToCompare) const {
return ( this -> name < itemToCompare. name) ;
}
operator const char * ( ) const {
return displayAs. c_str ( ) ;
}
} ;
int main ( ) {
set< ContactItem> setContacts;
setContacts. insert ( ContactItem ( "Jack Welsch" , "+1 7889 879 879" ) ) ;
setContacts. insert ( ContactItem ( "Bill Gates" , "+1 97 7897 8799 8" ) ) ;
setContacts. insert ( ContactItem ( "Angi Merkel" , "+49 23456 5466" ) ) ;
setContacts. insert ( ContactItem ( "Vlad Putin" , "+7 6645 4564 797" ) ) ;
setContacts. insert ( ContactItem ( "John Travolta" , "91 234 4564 789" ) ) ;
setContacts. insert ( ContactItem ( "Ben Affleck" , "+1 745 641 314" ) ) ;
DisplayContents ( setContacts) ;
cout << "Enter a name you wish to delete: " ;
string inputName;
getline ( cin, inputName) ;
auto contactFound = setContacts. find ( ContactItem ( inputName, "" ) ) ;
if ( contactFound != setContacts. end ( ) ) {
setContacts. erase ( contactFound) ;
cout << "Displaying contents after erasing " << inputName << endl;
DisplayContents ( setContacts) ;
} else {
cout << "Contact not found" << endl;
}
return 0 ;
}
3. 使用STL set 和multiset 的优缺点
优点
对需要频繁查找的应用程序来说,STL set 和multiset 很有优势,因为其内容是经过排序的,因此查找速度更快 缺点
容器在插入元素时进行排序,因此插入元素时有额外开销,因为需要对元素进行排序 在vector 中,可以使用新值替换迭代器(如std::find()返回的迭代器)指向的元素;但set 根据元素的值对其进行了排序,因此不能使用迭代器覆盖元素的值
4. STL 散列集合实现std::unordered_set 和std::unordered_multiset
使用基于散列的实现插入和排序时间固定的方式,使用散列函数来计算排序索引 将元素插入散列集合时,首先使用散列函数计算出一个唯一的索引,再根据该索引决定将元素放到哪个桶(bucket)中
# include <unordered_set>
# include <iostream>
using namespace std;
template < typename T >
void DisplayContents ( const T& cont) {
for ( auto element = cont. cbegin ( ) ; element != cont. cend ( ) ; ++ element) {
cout<< * element << ' ' ;
}
cout << endl;
cout << "Number of elements, size() = " << cont. size ( ) << endl;
cout << "Bucket count = " << cont. bucket_count ( ) << endl;
cout << "Max load factor = " << cont. max_load_factor ( ) << endl;
cout << "Load factor: " << cont. load_factor ( ) << endl << endl;
}
int main ( ) {
unordered_set< int > usetInt{ 1 , - 3 , 2017 , 300 , - 1 , 989 , - 300 , 9 } ;
DisplayContents ( usetInt) ;
usetInt. insert ( 999 ) ;
DisplayContents ( usetInt) ;
cout << "Enter int you want to check for existence in set: " ;
int input = 0 ;
cin >> input;
auto elementFound = usetInt. find ( input) ;
if ( elementFound != usetInt. end ( ) ) {
cout << * elementFound << " found in set" << endl;
} else {
cout << input << " not available in set" << endl;
}
return 0 ;
}