unordered_map, unordered_set instead of handwritten hash

unordered_map requires header files #include <unordered_map>
unordered_set requires header files #include <unordered_set>
Both are implemented based on hashes and are out of order , so the time complexity of adding , deleting, modifying and checking is O(1), which is faster than map and set , They are implemented based on a balanced binary tree (red-black tree), dynamically maintain an ordered sequence, and the time complexity is O(logn).

About how to write a hash table, please refer to: Hash table, string hash preliminary learning

Introduction to unordered_map

unordered_map<key,value> m;
Define a map type, the key is the primary key, and the value is the value. The mapping from the primary key to the value can be realized . It is an upgrade of a two-dimensional array. In a two-dimensional array, the primary key can only be of type int. The subscript starts from 0, and the map is OK. The primary key can be of any type.

The basic framework is as follows:

#include <iostream>
#include <unordered_map>
using namespace std;
typedef pair<string,int> PSI;
int main(){
    
    
    unordered_map<string,int> hash;
    
    return 0;
}

Common operations

hash.size()    Returns the current map container size (number of elements)
hash.empty()    determines whether the container is empty map, return an empty, non-empty return 0
hash.clear()    Clear all map elements
hash.erase(key)  delete key elements by
hash.erase(it)   deleting the element pointed iterator it may be used together in conjunction with the find function

1. Insert element
hash["lyh"]=20;

During the insertion process, first remove hash[key], and then re-assign it.
If you just write hash[key], if the key exists, there is only the retrieval process; if the key does not exist, it is the insertion process, and 0 is inserted by default.

hash.insert(PSI("lyh",40));
equivalent to:PSI t={"efg",456}; hash.insert(t);

Understand the usage of pair binary structure, you can also assign values ​​separately,t.first="efg"; t.second=456;

Both ① and ② can be inserted, but ① can be updated. Since the primary key in the map can only have one key, it cannot be repeated . When the key already exists in the map, the method ① can be used to update, but the method ② will not be inserted. Up.

2. Access elements
① Single access through the primary key
cout<<hash["lyh"];
② Through the iterator, all traversal or single access can be achieved

for (auto it=hash.begin();it!=hash.end();it++) 
        cout<<it->first<<" "<<it->second<<endl;

Auto is written in C++, which can automatically determine the type of the variable. In fact, it should be
unordered_map<string,int>::iterator it;

Pay attention to the access of method ①, which hash[key]is a search operation to return the value value of the current key. If the key does not exist in the hash, it will be inserted by default, and the initial value is 0. Therefore, in the case of uncertain whether the key exists , It is best to determine whether the key exists through the find or count function to avoid accidentally inserting it into the hash.

3. Judgment Primary keyExists
hash.find(key); Find whether the specified key exists, there is an iterator pointing to the key , otherwise it returns an iterator pointing to hash.end()

hash.count(key);Return the number of elements corresponding to the key. Since the map container key is not allowed to be repeated, the return value can only be 0 or 1 , which is also to determine whether the key-value element exists.

Introduction to unordered_set

unordered_set<int> hash;

The mapping in the map mentioned above is key->value. Both key and value can be of any type, but the primary key cannot be repeated;
and the set is more like an array, which can only be a mapping of int->value, that is, the primary key is only It can be an int type, similar to a vector container, but the value of a set is not allowed to be repeated . Moreover, it does not support indexing based on the primary key int, and can only be traversed through iterators, that is, set can only store value values .

The basic framework is as follows:

#include <iostream>
#include <unordered_set>

using namespace std;

int main()
{
    
    
    unordered_set<int> hash;

    return 0;
}

Common operations

hash.size();Get the number of elements
hash.empty();Determine whether it is empty
hash.clear();Clear the set
hash.erase(x);Delete the element with the value x
hash.erase(it);Delete the element pointed to by the iterator it
hash.erase(first,last);Delete the elements between [first, last) pointed to by the iterator

1. Insert element insert function
hash.insert(x);Insert element x into the collection

2. The access element
vector supports subscript access, and map supports primary key access. But set can only be accessed one by one based on iterators.

for (auto it=hash.begin();it!=hash.end();it++)
        cout<<(*it)<<endl;

In the same way, auto meansunordered_set<int>::iterator it;

3. Determine whether the element exists. The
map cannot determine whether the value exists. It is to determine whether the primary key key exists, and the primary key cannot be repeated; in the set, the primary key is determined, and the set determines whether the value value exists.

hash.find(x);Return an iterator, pointing to the element x, if it does not exist, point to hash.end();
hash.count(x);it. Determine whether the element x exists in the set. The return value is 1 or 0.

The commonly used operations in the hash table are inserting and fetching, judging whether a number exists, and deleting is rarely used. You can choose set or map simulation appropriately.

The difference between map and set is:

The map stores a pair of values ​​<type 1, type 2> (<key, value>), and the set stores a value.
Specifically, there is a big difference between the find function and the count function. The map is to find the primary key, and the set is to find the value.

Title description

On the basis of the description of the blue word title , introduce how to use unordered_map and unordered_set instead.

Brief title description:
Maintain a collection and support the following operations:

"I x", insert a number x;
"Q x", ask whether the number x has appeared in the set;

Now we need to perform N operations, and output the corresponding result for each query operation.

data range

1≤N≤105
−109≤x≤109

analysis:

What kind of set should we take? The input data x range to take to the scope of 2e9, the data from -1e9 to 1e9, but actually entered only 1e5 months if, as a barrel row that opened a huge array to store, obviously wasteful, so a discretization of The idea is to map the input data of [-1e9, 1e9] to the data of [1,1e5], so the hash is used. Previously, it was a handwritten hash. Now it uses the stl container, but the handwritten hash has a greater advantage and speed faster.

Use unordered_set to simulate

The set can only store the value value and can only be searched based on the value value, so each x should be inserted as the value value. Fortunately, the question asks whether x has appeared, not the number of times x appears, because the set container Cannot store duplicate elements.

#include <iostream>
#include <unordered_set>

using namespace std;

int main()
{
    
    
    unordered_set<int> hash;
    int num,x;
    char op[2];
    cin>>num;
    while (num--) {
    
    
        cin>>op>>x;
        if (op[0]=='I') hash.insert(x);
        else hash.count(x)?puts("Yes"):puts("No");
    }
    return 0;
}

Use unordered_map to simulate

unordered_map <key,value>, unordered_map inserts a binary structure <key,value> , which is mapped from key to value, and can only be found by key, not by value. Therefore, the x entered each time is used as the primary key key, and the value value maintains the number of times the primary key key appears. Since the question does not require the number of times, it is enough to store the 1 sign that has appeared.

#include <iostream>
#include <unordered_map>

using namespace std;

int main()
{
    
    
    unordered_map <int,int> hash;
    int num,x;
    char op[2];
    cin>>num;
    while (num--) {
    
    
        cin>>op>>x;
        if (op[0]=='I') hash[x]=1;  //根据key在那里标记是否插入过
        else hash.count(x)?puts("Yes"):puts("No");
    }        "hash.find(x)找到的是迭代器,找不到即指向hash.end()"
    return 0;
}

Guess you like

Origin blog.csdn.net/HangHug_L/article/details/114135343