简介
标准模板库中提供了一些容器类,以便在应用程序中进行频繁而快速的搜索。std::set 和 set::multiset 用于存储一组经过排序的元素,其查找元素的复杂度为对数,而unordered集合的插入和查找时间是固定的。
容器set可以让程序员在容器中快速查找键,键是存储在一维容器中的值。set只能存储唯一的键值,multiset可以存储重复的键值。为了实现快速搜索,其内部结构类像二叉树,位于set中特定位置的元素不能替换为值不同的新元素,这是因为set将把新元素同内部树中的其他元素进行比较,进而将其放在其他位置。
PS:要使用std::set和set::multiset类,需要包含头文件:
#include <set>
STLset和multiset的基本操作
实例化std::set对象
#include <set>
// used as a template parameter in set / multiset instantiation
template <typename T>
struct SortDescending
{
bool operator()(const T& lhs, const T& rhs) const
{
return (lhs > rhs);
}
};
int main ()
{
using namespace std;
// a simple set or multiset of integers (using default sort predicate)
set<int> setInts1;
multiset<int> msetInts1;
// set and multiset instantiated given a user-defined sort predicate
set<int, SortDescending<int> > setInts2;
multiset<int, SortDescending<int> > msetInts2;
// creating one set from another, or part of another container
set<int> setInts3(setInts1);
multiset<int> msetInts3(setInts1.begin(), setInts1.end());
return 0;
}
在set 或multiset中插入元素
#include <set>
#include <iostream>
using namespace std;
template <typename T>
void DisplayContents(const T& container)
{
for (typename T:: const_iterator element = container.begin();//不支持auto(C++11)可以这么写
element != container.end();
++element)
cout << *element << ' ';
cout << endl;
}
int main()
{
//set <int> setInts{ 202, 151, -999, -1 };
set <int> setInts;
setInts.insert(202);
setInts.insert(151);
setInts.insert(-999);
setInts.insert(-1);
setInts.insert(-1); // duplicate
cout << "Contents of the set: " << endl;
DisplayContents(setInts);
multiset <int> msetInts;
msetInts.insert(setInts.begin(), setInts.end());
msetInts.insert(-1); // duplicate
cout << "Contents of the multiset: " << endl;
DisplayContents(msetInts);
cout << "Number of instances of '-1' in the multiset are: '";
cout << msetInts.count(-1) << "'" << endl;
return 0;
}
在STLset或multiset中查找元素
#include <set>
#include <iostream>
using namespace std;
int main ()
{
//set<int> setInts{ 43, 78, -1, 124 };
set<int> setInts;
setInts.insert(43);
setInts.insert(78);
setInts.insert(-1);
setInts.insert(124);
// Display contents of the set to the screen
for (set<int>:: const_iterator element = setInts.begin();
element != setInts.end ();
++ element )
cout << *element << endl;
// Try finding an element
set<int>:: const_iterator elementFound = setInts.find (-1);
// Check if found...
if (elementFound != setInts.end ())
cout << "Element " << *elementFound << " found!" << endl;
else
cout << "Element not found in set!" << endl;
// finding another
set<int>:: const_iterator anotherFind = setInts.find (12345);
// Check if found...
if (anotherFind != setInts.end ())
cout << "Element " << *anotherFind << " found!" << endl;
else
cout << "Element 12345 not found in set!" << endl;
return 0;
}
PS:find()返回的迭代器与end()进行比较,以核实是否找到了指定的元素。如果该迭代器有效,便可以使用*elementFound访问它所指向的值。
删除STLset或multiset中的元素
#include <set>
#include <iostream>
using namespace std;
template <typename T>
void DisplayContents (const T& Input)
{
for (typename T::const_iterator element = Input.begin();
element != Input.end ();
++ element )
cout << *element << ' ';
cout << endl;
}
typedef multiset <int> MSETINT;
int main ()
{
//MSETINT msetInts{ 43, 78, 78, -1, 124 };
MSETINT msetInts;
msetInts.insert(43);
msetInts.insert(78);
msetInts.insert(78);
msetInts.insert(-1);
msetInts.insert(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;
}
PS:还可以将迭代器(如find()返回的迭代器)传递给erase(),这将删除单个元素
MSETINT :: iterator elementFound = msetInts.find(numberToErase);
if(elementFound != msetInts.end())
msetInts.erase(elementFound);
else
cout << "Element not found!" <<endl;
erase()还可以用于从multiset中删除指定范围内的元素
MSETINT :: iterator elementFound = msetInts.find(valueToErase);
if(elementFound != msetInts.end())
msetInts.erase(msetInts.begin(),elementFound);
一个使用STLset及其成员函数find和erase的电话簿
#include <set>
#include <iostream>
#include <string>
using namespace std;
template <typename T>
void DisplayContents (const T& container)
{
for (typename T :: const_iterator iElement = container.begin();
iElement != container.end();
++ iElement )
cout << *iElement << endl;
cout << endl;
}
struct ContactItem
{
string name;
string phoneNum;
string displayAs;
ContactItem (const string& nameInit, const string & phone)
{
name = nameInit;
phoneNum = phone;
displayAs = (name + ": " + phoneNum);
}
// used by set::find() given contact list item
bool operator == (const ContactItem& itemToCompare) const
{
return (itemToCompare.name == this->name);
}
// used to sort
bool operator < (const ContactItem& itemToCompare) const
{
return (this->name < itemToCompare.name);
}
// Used in DisplayContents via cout
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);
set<ContactItem>::iterator 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;
}
PS:std::set排序是在插入元素时进行的,在插入的时候使用operator<进行了排序。
使用STLset和multiset的优缺点
STLset和multiset在插入时对元素进行了排序,如果应用程序将频繁使用find( )函数的话,这种开销就是值得的。find()利用了内部二叉树的结构,在vector中,可以使用新值替换迭代器(如std::find( )返回的迭代器)指向的元素,但set根据元素的值对其进行了排序,因此不能使用迭代器覆盖元素的值,虽然通过编程可以实现这种功能。
STL散列集合实现std::unordered_set和std::unordered_multiset
因为set在插入时已经对元素进行了排序,所以在set中查找元素的时,所需要的时间不是与元素数成正比,而是与元素数的对数成正比。有一种插入和排序时间固定的的方式基于散列实现的。将元素插入散列集合时,首先利用散列函数计算出一个唯一的索引,再根据该索引决定将元素放到哪个桶(bucket)中.
#include<unordered_set>
#include <iostream>
using namespace std;
template <typename T>
void DisplayContents(const T& cont)
{
cout << "Unordered set contains: ";
for (typename T :: const_iterator element = cont.begin();
element != cont.end();
++ 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;
}
这个程序跑不起来,手上的编译器不支持C++11。这就比较难受了。那就这样吧,继续学习,后续会有补充的。