C++ multiset
multiset 是關聯容器的一種,是排序好的集合(元素已經進行了排序),并且允許有相同的元素。
不能直接修改 multiset 容器中元素的值。因為元素被修改后,容器并不會自動重新調整順序,于是容器的有序性就會被破壞,再在其上進行查找等操作就會得到錯誤的結果。因此,如果要修改 multiset 容器中某個元素的值,正確的做法是先刪除該元素,再插入新元素。
使用 multiset 必須包含頭文件 。multiset 類模板的定義如下:
template <class Key, class Pred = less<Key>, class B = allocator<Key> > class multiset {... };該模板有三個類型參數:Key、Pred 和 B。類型參數可以有默認值,默認值就是某種類型。例如,Pred 類型參數的默認值就是 less 類型,B 的默認值就是 allocator 類型。
第一個類型參數說明 multiset 容器中的每個元素都是 Key 類型的。第二個類型參數 Pred 用于指明容器中元素的排序規則,在被實例化后,Pred 可以是函數對象類,也可以是函數指針類型。
multiset 內部在排序時定義了一個變量Pred op,根據表達式op(x, y)來比較兩個元素 x、y 的大小。該表達式的值為 true,則說明 x 比 y 小。Pred 的默認值是 less,less 是 STL 中的函數對象類模板,其定義如下:
template <class_Tp> struct less {bool operator() (const _Tp &__x, const _Tp &__y) const{ return __x < __y; } };這說明,在默認情況下,multiset 容器中的元素是用<運算符比較大小的。例如,假設 A 是一個類的名字,可以定義一個如下的容器對象:
multiset <A> s;由于 multiset 的類型參數可以使用默認值,因此上面的語句等價于:
multiset < int, less<A>, allocator<A> > s;模板類 multiset < A, less, allocator > 的 insert 成員函數可以用來插入一個元素。 插入過程中需要進行元素之間的比較,可以認為 insert 成員函數中定義了一個變量 less op,用 op(x, y) 來比較元素 x、y 的大小。歸根到底,還是用<運算符比較 x、y 的大小。 因此,<運算符必須經過適當重載,才可以向 multiset 容器中插人元素。
下面的程序 會編譯出錯:
#include <set> using namespace std; class A{}; int main(){multiset <A> a;a.insert( A() ); //編譯出錯,因為不能用“<”運算符比較兩個A對象 }multiset 的成員函數
| iterator find (const T & val); | 在容器中查找值為 val 的元素,返回其迭代器。如果找不到,返 回 end() |
| iterator insert( const T & val); | 將 val 插入容器中并返回其迭代器 |
| void insert(iterator first, iterator last); | 將區間 [first, last) 中的元素插人容器 |
| int count( const T & val); | 統計有多少個元素的值和 val 相等 |
| iterator lower_bound( const T & val); | 查找一個最大的位置 it,使得 [begin(), it) 中所有的元素者比 val 小 |
| iterator upper_bound( const T & val); | 查找一個最小的位置 it,使得 [it, end()) 中所有的元素都比 val 大 |
| pair <iterator, iterator > equal_range (const T & val); | 同時求得 lower_bound 和 upper_bound |
| iterator erase(iterator it); | 刪除 it 指向的元素,返回其后面的元素的迭代器 |
| iterator erase(iterator first, iterator last); | 刪除區間 [first, last),返回 last |
multiset 及 set 中的 find 和 count 并不是用==運算符比較元素是否和待查找的值相等的。它們進行比較的原則是:如果x比y小和y比x小同時為假,就認為 x 和 y 相等。
下面通過一個例子說明 multiset 的用法。
#include <iostream> #include <set> //使用multiset須包含此頭文件 using namespace std; template <class T> void Print(T first, T last) {for (; first != last; ++first)cout << *first << " ";cout << endl; } class A { private:int n; public:A(int n_) { n = n_; }friend bool operator < (const A & a1, const A & a2){ return a1.n < a2.n; }friend ostream & operator << (ostream & o, const A & a2){ o << a2.n; return o; }friend class MyLess; }; class MyLess { public:bool operator() (const A & a1, const A & a2) //按個位數比較大小{ return (a1.n % 10) < (a2.n % 10); } }; typedef multiset <A> MSET1; //MSET1 用“<”運算符比較大小 typedef multiset <A, MyLess> MSET2; //MSET2 用 MyLess::operator() 比較大小 int main() {const int SIZE = 6;A a[SIZE] = { 4, 22, 19, 8, 33, 40 };MSET1 m1;m1.insert(a, a + SIZE);m1.insert(22);cout << "1)" << m1.count(22) << endl; //輸出 1)2cout << "2)"; Print(m1.begin(), m1.end()); //輸出 2)4 8 19 22 22 33 40MSET1::iterator pp = m1.find(19);if (pp != m1.end()) //條件為真說明找到cout << "found" << endl; //本行會被執行,輸出 foundcout << "3)"; cout << *m1.lower_bound(22)<< "," << *m1.upper_bound(22) << endl; //輸出 3)22,33pp = m1.erase(m1.lower_bound(22), m1.upper_bound(22));//pp指向被刪元素的下一個元素cout << "4)"; Print(m1.begin(), m1.end()); //輸出 4)4 8 19 33 40cout << "5)"; cout << *pp << endl; //輸出 5)33MSET2 m2; //m2中的元素按n的個位數從小到大排序m2.insert(a, a + SIZE);cout << "6)"; Print(m2.begin(), m2.end()); //輸出 6)40 22 33 4 8 19return 0; }第 30 行,MSET2 類的排序規則和 MSET1 不同。MSET2 用 MyLess 定義排序規則,即 n 的個位數小的元素排在前面。
第 43、44 行,lower_bound 返回的迭代器指向第一個 22,upper_bound 返回的迭代器指向 33。
第 45 行,刪除所有值為 22 的元素。erase 成員函數刪除一個元素后,返回下一個元素的迭代器應該是很合理的,但是 C++ 標準委員會認為,返回下一個元素的迭代器也是需要時間開銷的,如果程序員不想要這個返回值,那么這個開銷就是浪費的——因此在遵循 C++ 標準的 Dev C++ 中,本行無法編譯通過。但是微軟公司認為應該對這一點做出改進,因此 Visual Studio 2010 將 erase 成員函數處理成返回被刪元素下一個元素的迭代器。
不論在哪種編譯器中,用 erase 成員函數刪除迭代器 i 指向的元素后,迭代器 i 即告失效, 此時不能指望 ++i 后 i 會指向被刪除元素的下一個元素;相反,++i 可能立即導致出錯。如果想要得到被刪除元素后面那個元素的迭代器,可以在刪除前獲取其迭代器并保存起來(這同樣適用于 set、map、multimap 的 erase 成員函數)。事實上,如果得到了某關聯容器的迭代器,則該迭代器并不會因為容器中元素的插入以及其他元素的刪除而失效。只要該迭代器指向的元素沒有被刪除,就可以一直使用它。
總結
以上是生活随笔為你收集整理的C++ multiset的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java @SafeVarargs注解
- 下一篇: Spring Boot applicat