1. 程式人生 > >總結map和set增刪查改的使用

總結map和set增刪查改的使用

在STL中map和set都是關聯式容器,vector和list是序列式容器,在今天的這篇文章中主要介紹的是map和set的基本用法。
一、set
set是一種key型別的集合結構,所以set是不允許有重複元素的一種結構,set中所有元素的key值都會被自動排序為升序。set和multiset都包含在標頭檔案#include<set>中,set和multiset的底層都是用紅黑樹實現的,但是set的底層插入機制時insert_unique,multiset的底層插入機制時insert_equal

template < class Key, class Compare = less<Key
>, class Allocator = allocator<Key> > class set;
  • 1
  • 2

由上述定義可知,set也是一種模板,它的第一個引數Key代表的是鍵值的型別;第二個引數是一個仿函式,它傳入的是鍵值的比較方式,決定其是升序還是降序;第三個引數是空間配置器。我們主要關心的是set的第一個引數。
set的常用操作:
set的常用操作

在介紹set和map的常用操作之前,先來介紹一種模板型別pair,每個pair可以儲存兩個值,這兩個值可以是任意型別的,pair的兩個成員分別是first和second,且pair包含在標頭檔案#include<utility>

中。

pair

1、insert,set的插入有三種類型
1.1、pair<iterator,bool> insert(const value_type& x)

其中的value_type是鍵值的型別,這個版本的插入會返回一個pair型別的物件,其中pair對second成員為false說明插入失敗,該元素已經存在,反之則說明插入成功。pair的first成員指向的是要插入位置的迭代器,如果second是false,則first就是這個已經存在元素的迭代器;如果second成員是true,則first就會指向插入位置的迭代器。

1.2、iterator insert(iterator position,const valut_type& val)

postion的型別是一個迭代器的位置,vla表示要插入的資料。如果插入成功,則會返回一個新插入位置的迭代器,否則的話返回這個傳入的迭代器。

1.3、插入一段迭代器區間

template<class InputIterator>
void insert(InputIterator first,InputIterator last)
  • 1
  • 2

2、erase,刪除
2.1、void erase(iterator position)
刪除一個迭代器位置
2.2、size_type erase(const value_type& val)
刪除成功返回1,刪除失敗返回0
2.3、void erase(iterator first,iterator last)
刪除從first到last的一段迭代器空間
3、find,查詢

   iterator find(const value_type& val) const;
  • 1

如果找到的話就返回這個位置的迭代器,否則就返回end
4、count,統計鍵值出現的次數

  size_type count(const value_type& val) const;
  • 1

由於set裡面不允許有重複出現的鍵值,所以count的返回結果就只有0和1兩個結果,0就表示不存在,1表示存在。這個功能不就和empty功能重複了嗎?當然不會啦!count這個介面一般在multiset中使用的最多,這個主要是為了統一介面罷了。
5、set的迭代器set::iterator是一種const_iterator,所以不允許通過迭代器修改set中的值。
當然了,set中的介面還有很多,在這裡只介紹這幾個。

multiset的常用操作:
multiset的特性和用法和set的用法完全相同,唯一的差別就是multiset是允許鍵值重複出現的。
1、insert,插入

iterator insert(const value_type& val)
  • 1

如果直接插入一個鍵值的話,在multiset中返回的是插入元素位置的迭代器。
2、count
multiset中可以出現重複的鍵值。count統計的是相同鍵值出現的次數。如果count的結果為0則表示沒有出現,如果不為0則表示出現的次數 。
下面是我寫的一個關於set操作的簡單例子:

void TestSet()
{
    //set是K型別的
    set<string> Myset;
    Myset.insert("left");
    Myset.insert("right");
    Myset.insert("high");
    Myset.insert("low");
    Myset.insert("right");
    Myset.insert("right");
    cout<<"size?"<<Myset.size()<<endl;  //4
    cout<<"max_size?"<<Myset.max_size()<<endl;
    set<string>::iterator it=Myset.begin();
    while(it != Myset.end())
    {
        cout<<*it<<" ";
        ++it;
    }
    cout<<endl;
    cout<<Myset.count("right")<<endl;   //1 統計right出現的次數,set是去重的
    it=Myset.find("left");
    if(it != Myset.end())    //找到了
    {
        cout<<*it<<endl;     //left
    }
    //Myset.erase(it);      //刪除一個迭代器
    Myset.erase(it,Myset.end());   //刪除兩個迭代器之間的範圍
}

二、map
map是一種Key(鍵)、value(值)形式的結構,用於儲存鍵和值組成的條目集合。它要求鍵值必須是唯一的,值可以不唯一,同一個值可以對映到多個鍵上(所以map在vlaue層面上是允許重複的,這一點不同於set)。所有的元素都會根據鍵值自動排序。map中的所有元素都是pair,同時擁有鍵值(Key)和實值(value),pair的first被視為鍵值,second被當做實值。我們是不可以修改map的key值的,但是我們可以更改map的vlaue值。map的底層是用紅黑樹實現的,它的insert機制是一種insert_unique()

template<class Key,class T,class Compare=less<Key>,class Alloc=allocator<pair<const Key,T> > >
  • 1

map也是一個模板,他有四個模板引數型別,第一個是鍵值的型別(key);第二個是實值的型別(value);第三個是一個仿函式,它傳入的是鍵值的比較方式,預設是升序排列;第四個是空間配置器。
map的常用操作:

map的常用操作

1、insert,插入
1.1、pair<iterator,bool> insert(const value_type& val);
插入一個value_type型別,返回值是一個pair型別。 pair

template<class InputIterator>
    void insert(InputIterator first,InputIterator last);
  • 1
  • 2

2、erase
2.1、void erase(iterator position)
刪除的是position迭代器位置的元素。
2.2、size_type erase(const key_type& k)
刪除這個鍵值所在的位置,成功返回1,失敗返回0。
2.3、void erase(iterator first,iterator last);
刪除一段從first到last的迭代器區間
3、find

  iterator find(const key_type& k)
  • 1

如果查詢成功的話則返回這個元素的迭代器,否則返回end,所以在使用find返回的迭代器之前要先判斷一下。
4、count

size_type count(const key_type& k)const
  • 1

map中的count與set的count功能一樣。
5、operator[]

mapped_type& operator[](const key_type& k)
  • 1

map中的operator[]是最常用的,map中operator[]的底層實現利用的是insert來實現的。
operator

multimap:
multimap與map的特性及用法完全相同,但是multimap是允許鍵值重複的。multimap和 map都包含在標頭檔案#include<map>中,它們的底層也是用紅黑樹實現的,它的insert機制是insert_equal。它的count與multiset的count的用法及作用完全一樣。下面看一下他們的不同:
1、insert

iterator insert(const value_type& val)
  • 1

如果插入一個元素的話,multimap會返回一個這個插入位置的迭代器。
2、count
count與multiset的count完全相同,multimap中的count統計的是鍵值出現的次數。
3、multimap中沒有過載operator[]。

簡單的例子測試map的基本操作:利用map實現一個字典樹,利用map統計出現次數最多的前k個水果。

//template<class K,class V>    //自己編寫的一個簡單的pair
//struct pair
//{
//  K first;
//  V second;
//  pair(const K& key,const V& value)
//      :first(key)
//      ,second(value)
//  {}
//};

//構造一個pair的物件返回
template<class K,class V>
pair<string,int> make_pair(const K& key,const V& value)
{
    return pair<string,int>(key,value);
}

void TestDict()
{
    //map是K,V型別的
    map<string,string> dict;
    dict.insert(pair<string,string>("value","值"));
    dict.insert(pair<string,string>("left","左邊"));
    dict.insert(pair<string,string>("right","右邊"));
    dict.insert(pair<string,string>("up","上"));
    dict.insert(pair<string,string>("down","下"));
    dict["left"]="剩餘";    //也可以使用operator[]來插入或者修改資料的value
    map<string,string>::iterator it=dict.begin();
    while(it != dict.end())
    {
        cout<<(*it).first<<":"<<(*it).second<<endl;
        ++it;
    }
    cout<<endl;

}
vector<int> GetTopKFruits(const vector<string>& fruits)
{
    typedef map<string,int> Map;
    typedef map<string,int>::iterator MapIt;
    vector<int> v;
    //map<string,int> countMap;
    Map countMap;
    for(size_t i=0;i<fruits.size();i++)
    {
        //方法一,find和insert都遍歷了這個map,效率不行,但是方便理解,簡潔直觀
        //map<string,int>::iterator it=countMap.find(fruits[i]);
        //if(it != countMap.end())    //找到了
        //{
        //  it->second++;
        //}
        //else    //沒有找到則插入到map中
        //{
        //  //countMap.insert(pair<string,int>(fruits[i],1));
        //  countMap.insert(make_pair(fruits[i],1));
        //}

        //方法二,只查詢一次,利用返回pair型別的insert函式
        //pair<MapIt,bool> res=countMap.insert(make_pair(fruits[i],1));
        //if(res.second == false)    //找到了,插入失敗
        //{
        //  res.first->second++;
        //}

        //方法三,利用operator[]來實現,operator[]的底層是利用insert來實現的,具體可參考前面提到的operator[]的實現原理
        countMap[fruits[i]]++;
    }
    map<string,int>::iterator it=countMap.begin();
    while(it != countMap.end())
    {
        v.push_back(it->second);
        ++it;
    }
    return v;
}
void TestFruits()
{
    vector<string> fruits;
    fruits.push_back("菠蘿");
    fruits.push_back("梨");
    fruits.push_back("水蜜桃");
    fruits.push_back("梨");
    fruits.push_back("菠蘿");
    fruits.push_back("水蜜桃");
    fruits.push_back("香蕉");
    fruits.push_back("菠蘿");
    fruits.push_back("梨");
    fruits.push_back("水蜜桃");
    fruits.push_back("梨");
    fruits.push_back("菠蘿");
    fruits.push_back("水蜜桃");
    fruits.push_back("香蕉");

    vector<int> res=GetTopKFruits(fruits);
    for(size_t i=0;i<res.size();i++)
    {
        cout<<res[i]<<" ";
    }
    cout<<endl;   // 4 4 4 2
}