1. 程式人生 > >記錄下map 和unordered_map的用法

記錄下map 和unordered_map的用法

                                    “ 多做善事才是好運的根本!”

2018年9月14日

8月、9月、10月~

挺過去,一切都會好的,

但是竭盡全力,

因為,你後悔不起~

記錄下C++、資料結構中的一些知識用法吧:

我們都知道,容器是存放資料的地方,常見的容器有序列式容器和關聯式容器,序列式容器,即其中的元素不一定有序,但可以被排序,比如vector、list、queue、stack、heap、priority_queue;而關聯式容器內部結構基本上是一個平衡二叉樹。所謂關聯,指每個元素都有一個鍵值和一個實值<key,value>,元素按照一定的規則存放。比如RB-tree、set、map、unordered_map、hashtable、hash_map、hash_set。

接下來著重介紹map和unordered_map:(用的最多)

map: #include <map> unordered_map: #include <unordered_map>

算了,說一下map和set的區別吧,set:其內部元素會根據元素的鍵值自動被排序;區別於map,它的鍵值就是實值,而map可以同時擁有不同的鍵值和實值。

map:

一對一的方式來儲存資料,<關鍵字,對映值>,其內部通過R-B tree(紅黑樹)實現,而且會根據key值來自動將資料排序,因此map內部的所有元素都是有序的,紅黑樹的每一個節點都代表著map的一個元素。因此,對於map進行的查詢,刪除,新增等一系列的操作都相當於是對紅黑樹進行的操作。另外,map比hash_map(未進入stl)穩定,但是一般沒有hash_map快。其時間複雜度:O(log n)

unordered_map:

unordered_map底層用一個雜湊表(也叫散列表,通過把關鍵碼值對映到Hash表中一個位置來訪問記錄,查詢的時間複雜度可達到O(1),其在海量資料處理中有著廣泛應用)來實現。因此,其元素的排列順序是無序的。時間複雜度:O(1)常數級

明確下各自的優缺點:

map:

  1. 優點: 
    1. 有序性,這是map結構最大的優點,其元素的有序性在很多應用中都會簡化很多的操作
    2. 紅黑樹,內部實現一個紅黑書使得map的很多操作在lgn的時間複雜度下就可以實現,因此效率非常的高
  2. 缺點: 空間佔用率高,因為map內部實現了紅黑樹,雖然提高了執行效率,但是因為每一個節點都需要額外儲存父節點、孩子節點和紅/黑性質,使得每一個節點都佔用大量的空間

  3. 適用處:對於那些有順序要求的問題,用map會更高效一些

unordered_map:

  1. 優點: 因為內部實現了雜湊表,因此其查詢速度非常的快
  2. 缺點: 雜湊表的建立比較耗費時間
  3. 適用處:對於查詢問題,unordered_map會更加高效一些,因此遇到查詢問題,常會考慮一下用unordered_map

舉例:(包括map的宣告、建立、遍歷)

leetcode 1兩數之和

/*
題目:leetcode 1 Two Sum 兩數之和
      從給定的一組數中找到兩個數的和為target.返回兩個數的序號,假設每次輸入只有一組解
時間:2018年9月14日 12:16:34
思路:1.暴力搜尋,對於每個數去找後面和它的和為target的數,如果找到了就返回,時間複雜度O(n^2)
      2.hash:先進行hash對映,<key,value>為 <nums[i], i>,對於每一個數,可以在O(1)的時間找到
  即:用空間來彌補時間,建立使用一個HashMap,來建立數字和其下標位置之間的對映,也就是我求得一個數就直接能知道它的下標。
      我們都知道HashMap是常數級的查詢效率,這樣,我們在遍歷陣列的時候,用target減去遍歷到的數字,就是另一個需要的數字了,
      直接在HashMap中查詢其是否存在即可,注意要判斷查詢到的數字不是第一個數字,比如target是4,遍歷到了一個2,那麼另外一個2不能是之前那個2,
      整個實現步驟為:先遍歷一遍陣列,建立HashMap對映,然後再遍歷一遍,開始查詢,找到則記錄index。
*/


#include <bits/stdc++.h>

using namespace std;

//法一:暴力搜尋
class Solution {
public:
    vector<int> twoSum(vector<int> &num, int target) {
        vector<int> v;
        for(int i=0;i<num.size();++i)
        {
            for(int j=i+1;j<num.size();++j)
            {
                if(num[i]+num[j]==target)
                {
                    v.push_back(i);
                    v.push_back(j);
                    break;
                }
            }
        }
        return v;
    }
};

//法二:hash表
class Solution {
public:
    vector<int> twoSum(vector<int> &num, int target) {
        vector<int> v;
        unordered_map<int,int> m;//宣告hash圖
        for(int i=0;i<num.size();++i)//建立hash圖
        {
            m[num[i]]=i;
        }
        
        for(auto &it:m)//遍歷hash圖;
            cout<<it.first<<" "<<it.second<<endl;
        for(int i=0;i<num.size();++i)
        {
            int t=target-num[i];
            if(m.count(t)&& m[t]!=i)//if(m.find(t)!=m.end()&&m[t]!=i)
            {
                v.push_back(i);
                v.push_back(m[t]);
                break;
            }
        }
        return v;
    }
};

int main()
{
    vector<int> a={1,6,4,5,7};
    Solution so;
    vector<int> res;
    res=so.twoSum(a,9);
    for(auto i:res)//遍歷容器的簡單方法
        cout<<i<<" ";
    return 0;
}

一定要看懂,理解!

裡面的寫法很值得銘記。

最後,祝福所有努力的人,都會有好運!