1. 程式人生 > >STL中的關聯式容器解析

STL中的關聯式容器解析

"  其實真正能擊垮你的,

   往往不是那些突如其來的滅頂之災,

   而是壓在你心底

   那些看似不值一提,日積月累的心事,

   在某一瞬間,使你徹底崩潰,成為壓垮你的最後一根稻草。"

這幾天,突然一下子想明白了

隨波逐流不是我的風格,我需要堅持一些東西,需要做一些不一樣的東西,即使是在無限的誘惑裡~

很難,真的很難,

加油!

正題:記錄STL中的map 和set用法!

map

map和set一樣是關聯式容器,它們的底層容器都是紅黑樹,區別就在於map的值不作為鍵,鍵和值是分開的。它的特性如下:

  • map以RBTree作為底層容器
  • 所有元素都是鍵+值存在
  • 不允許鍵重複
  • 所有元素是通過鍵進行自動排序的
  • map的鍵是不能修改的,但是其鍵對應的值是可以修改的

   map<key, value>   m;   

set

set是一種關聯式容器,其特性如下:

  • set以RBTree作為底層容器
  • 所得元素的只有key沒有value,value就是key
  • 不允許出現鍵值重複
  • 所有的元素都會被自動排序
  • 不能通過迭代器來改變set的值,因為set的值就是鍵

   set<int> s;

∴:map和set的共同點在於:都是有序的無重複的key值,而且底層都是基於R-B Tree。

說明:pair是一個結構體型別,裡面的兩個成員變數的型別可以通過模板給定;換句話說,pair是一種K-V資料型別,可以定義此型別的變數

例:map<string,int> m;

       pair<string,int> v(string("zhangheng",2));

       m.insert(v);

       //構造一個int型別的set        set<int> s;         //插入幾個元素       s.insert(1);       s.insert(2);       s.insert(6);         //測試insert()的返回值       pair<set<int>::iterator, bool> ret;       ret = s.insert(4);//set中還沒有4這個元素,插入成功,返回插入節點的迭代器和TRUE       ret = s.insert(4);//set中已經存在了4,插入失敗,返回的是元素4的迭代器和FALSE

常用的容器操作:插入、刪除、儲存、遍歷、查詢、排序

C++中的STL之所以牛B,是因為STL封裝了許多複雜的資料結構和演算法,以及大量常用的資料結構操作。vector封裝了資料,list封裝了連結串列,map和set封裝了二叉樹。

接下來,分別舉例來研究map和set的用法:

●map的操作

map<string, int> m;
m["messi"] = 1;
m["jams"] = 2;
m["jack"] = 3;

//插入操作
pair<string, int> value("json", 4);
m.insert(value);

//輸出集合中的元素(遍歷map中的元素)
for(map<string, int>::iterator iter = m.begin(); iter != m.end(); iter ++){
    cout<<"key : "<<iter->first<<endl;
    cout<<"value : "<<iter->second<<endl;
}

// 修改資料的兩種方式:
// 方式1:
m[2] = "Ma";
// 方式2:
m->second = "Yuan";
print(mapStu1);

//刪除操作
//1,刪除指定的鍵值
m.erase("jams");
 
//2,刪除迭代器指向的元素
m.erase(m.begin());
it = m.find(2);
m.erase(it);
 
//3,刪除指定區間的元素
m.erase(m.begin(), m.end())

//查詢元素
//給定一個鍵值,如果查詢成功函式返回指向這個元素的迭代器,否則返回end()
map<string, int>::iterator iter = myMap.find("messi");
if(iter != myMap.end()){
    cout<<"key : "<<iter->first<<endl;
    cout<<"value : "<<iter->second<<endl;
}


●set的操作

例:把只包含質因子2、3和5的數稱作醜數(Ugly Number)。       比如6、8都是醜數,但14不是,因為它包含質因子7。把1當做是第一個醜數。求按從小到大的順序的第N個醜數。  

/*
題目:把只包含質因子2、3和5的數稱作醜數(Ugly Number)。
      例如6、8都是醜數,但14不是,因為它包含質因子7。把1當做是第一個醜數。求按從小到大的順序的第N個醜數。
所以:從1開始的10個醜數分別為1,2,3,4,5,6,8,9,10,12。
      你可能疑惑:8的因子有1、2、4、8;那怎麼能是醜數呢?是因為只是要求一個數的質數因子只能是2,3,5
時間:2018年x月x日 08:08:08
思路:一:暴力(遍歷)
          1)設定一個計數器用來統計出現的醜數的個數
          2)從1開始遍歷每個整數,推斷是否是醜數,假設是醜數則計數器加1。否則遍歷下一個整數。
          注意,怎麼判斷一個數是不是醜數,迴圈除以2直到不能整除,接著迴圈除以3再到不能整除,再迴圈除以5,若還是不能整除,則不是醜數。
          例:醜數12 12/2 = 6;6/2 = 3;3/2 不能整除;3/3 = 1; 結束,12是醜數;非醜數26 26/2 = 13;13/2 不能整除;13/3 不能整除;13/5 不能整除;結束,26不是整數
          3)當計數器的值=N時,停止遍歷。輸出醜數。
      二:想辦法從上一個醜數判斷出下一個醜數,而不須要從1開始遍歷再判斷。
          即:所有的醜數都是由前面醜數乘上2,或3,或5得到的。
          1)先求出醜數i之前的所有醜數與2,3,5的乘積,找出大於i的最小值作為新產生的醜數。
*/

#include <bits/stdc++.h>

using namespace std;
/*
//法一:暴力
class Solution {
public:
    void GetUglyNumber_Solution(int index) {
        //找到第index個醜數
        int i,count =0;
        if (index < 1)
        {
            cout << "error input " << endl;
            exit(0);
        }
        for (i=1;i< INT_MAX && count< index;i++)
        {
            if ( IsUgly(i) )
            {
                count++ ;
                //cout << i << " " ;
            }
        }
        cout << i-1 << endl;
    }
    //遍歷法找醜數
    bool IsUgly(int num)//判斷是否是
    {
        while (num %2 == 0)
        {
            num /= 2;
        }
        while (num %3 == 0)
        {
            num /= 3;
        }
        while (num %5 == 0)
        {
            num /= 5;
        }
        if (num == 1)
            return true;
        else
            return false;//not an ugly number
    }
};
*/

//法二:建議此種方法,所有的醜數都是有現有醜數乘以2,3,5得到的
class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        if (index <= 0)
        {
            return 0;
        }
        vector<int> v(index);
        v[0]=1;
        vector<int>::iterator it2=v.begin();
        vector<int>::iterator it3=v.begin();
        vector<int>::iterator it5=v.begin();
        int count=1;
        while(count<index)
        {
            int m=min(*it2 * 2,min(*it3 * 3,*it5 * 5));
            v[count]=m;
            //下邊就是更新2,3,5的指標
            if (*it2 * 2 <= m)//小於等於當前最大的醜數,則要更新
            {                 //因為在這個指標之前的數乘以2都比當前的最大丑數小,
                it2++;
            }
            if (*it3 * 3 <= m)
            {
                it3++;
            }
            if (*it5 * 5 <= m)
            {
                it5++;
            }
            count++;
        }
        int ugly = v[count - 1];
        return ugly;
    }
};
/*
//法三:此種方法花費時間太長,MAX只能設定較小的數才可以,適用於求Number較小的情況。不建議使用,但是它用set的思想值得學習。
class Solution {
public:
    void GetUglyNumber_Solution(int Index)
    {
        const int MAX = 100000;//const int MAX = INT_MAX/5;
        int i,j;
        set<int> s;
        set<int>::iterator it;
        s.insert(1);
        for (i=1 ; i<MAX ; i++)
        {
            if (s.find(i) != s.end() )
            {
                s.insert(2*i) ;
                s.insert(3*i) ;
                s.insert(5*i) ;
            }
        }
        for (it = s.begin(),j=0;it!= s.end()&&j<Index-1;it++,j++)
            cout << *it << " ";
        cout<< endl<< *it << endl;
    }
};
*/
int main()
{

	int Number;
	cout << "Input a number : " ;
	cin >> Number ;
	Solution so;
	int result=so.GetUglyNumber_Solution(Number);
	cout<<result<<endl;
	return 0;
}

好嘞!