Struct of Hash String

Revision en3, by MohammadParsaElahimanesh, 2021-03-17 11:32:23

In the name of Allah

--------------------

Hello my friends ! I have a prize for you, Actually I always have a problem with KMP. So I try to use hash string instead. I think it wood be great if we have a struct like hash and can easily work with it. So I make it ! here I implemented hash struct with C++ & you can have fun with it.

#include <bits/stdc++.h>

using namespace std;

template <typename X, typename Y, typename Z>
long long int Pow(const X &a, const Y &b, const Z &mod) /// # O(log(b))
{
    if(b == 0) return 1LL;
    long long int x = Pow(a,b/2,mod);
    return b%2 == 0? x*x%mod : (long long int)a * (x * x % mod) % mod;
}

bool ready = false;
const long long int MAX_Hash = 1e6 + 5;
const long long int mod1 = 1e9 + 7;
const long long int mod2 = 1e9 + 9;
const long long int C = 257LL;
long long int C1[MAX_Hash];
long long int C2[MAX_Hash];
long long int pow1[MAX_Hash];
long long int pow2[MAX_Hash];

void fill_C()
{
    C1[0] = C2[0] = 1LL;
    for(int i = 1; i < MAX_Hash; i++)
    {
        C1[i] = (C1[i-1] * C) % mod1;
        C2[i] = (C2[i-1] * C) % mod2;
    }
}

void fill_pow()
{
    pow1[0] = pow2[0] = 1LL;
    pow1[1] = Pow(C,mod1-2,mod1);
    pow2[1] = Pow(C,mod2-2,mod2);
    for(int i = 2; i < MAX_Hash; i++)
    {
        pow1[i] = pow1[i-1] * pow1[1] % mod1;
        pow2[i] = pow2[i-1] * pow2[1] % mod2;
    }
}

void GetReady()
{
    ready = true;
    fill_C();
    fill_pow();
}

struct Hash
{
    long long int val1 = 0, val2 = 0, S = 0;

    Hash() /// # O(1)
    {
        if(!ready)GetReady();
    }

    Hash(const char &x) /// # O(1)
    {
        Hash();
        push_back(x);
    }

    Hash(char *s, const char *e) /// # O(Len)
    {
        Hash();
        push_back(s,e);
    }

    Hash(const string &s) /// # O(len)
    {
        Hash();
        push_back(s);
    }

    Hash(const Hash &A) /// # O(1)
    {
        Hash();
        push_back(A);
    }

    void clear() /// # O(1)
    {
        S = val1 = val2 = 0LL;
    }

    void push_back(const char &x) /// # O(1)
    {
        S++;
        val1 *= C1[1];
        val1 += (long long int)x;
        val1 %= mod1;
        val2 *= C2[1];
        val2 += (long long int)x;
        val2 %= mod2;
    }

    void push_back(const string &s) /// # O(len)
    {
        for(auto u: s)
            push_back(u);
    }

    void push_back(char *s, const char *e) /// # O(len)
    {
        while(s != e)
        {
            push_back(*s);
            s++;
        }
    }

    void push_back(const Hash &A) /// # O(1)
    {
        val1 *= C1[A.S];
        val1 += A.val1;
        val1 %= mod1;
        val2 *= C2[A.S];
        val2 += A.val2;
        val2 %= mod2;
        S += A.S;
    }

    void push_front(const char &x) /// # O(1)
    {
        val1 += (long long int)x * C1[S];
        val1 %= mod1;
        val2 += (long long int)x * C2[S];
        val2 %= mod2;
        S++;
    }

    void push_front(const string &s) /// # O(len)
    {
        for(int i = s.size()-1; i >= 0; i--)
            push_front(s[i]);
    }

    void push_front(const char *s, char *e) /// # O(len)
    {
    if(e == s)return;
        do
        {
            e--;
            push_back(*e);
        }while(s != e);
    }

    void push_front(const Hash &A) /// # O(1)
    {
        val1 += A.val1 * C1[S];
        val1 %= mod1;
        val2 += A.val2 * C2[S];
        val2 %= mod2;
        S += A.S;
    }

    void operator+=(const Hash &A) /// # O(1)
    {
        push_back(A);
    }

    void operator+=(const char &x) /// # O(1)
    {
        push_back(x);
    }

    void operator+=(const string &s) /// # O(len)
    {
        push_back(s);
    }

    void pop_back(const char &x) /// # O(1)
    {
        S--;
        val1 -= (long long int)x;
        val1 *= pow1[1];
        val1 = ((val1%mod1)+mod1)%mod1;
        val2 -= (long long int)x;
        val2 *= pow2[1];
        val2 = ((val2%mod2)+mod2)%mod2;
    }

    void pop_back(const string &s) /// # O(len)
    {
        for(int i = s.size()-1; i >= 0; i--)
            pop_back(s[i]);
    }

    void pop_back(const char *s, char *e) /// # O(len)
    {
        if(e == s)return;
        do
        {
            e--;
            pop_back(*e);
        }while(s != e);
    }

    void pop_back(const Hash &A) /// # O(1)
    {
        S -= A.S;
        val1 -= A.val1;
        val1 *= pow1[A.S];
        val1 = ((val1%mod1)+mod1)%mod1;
        val2 -= A.val2;
        val2 *= pow2[A.S];
        val2 = ((val2%mod2)+mod2)%mod2;
    }

    void pop_front(const char &x) /// # O(1)
    {
        S--;
        val1 -= (long long int)x * C1[S];
        val1 = ((val1%mod1)+mod1)%mod1;
        val2 -= (long long int)x * C2[S];
        val2 = ((val2%mod2)+mod2)%mod2;
    }

    void pop_front(const string &s) /// # O(len)
    {
        for(auto u: s)
            pop_front(u);
    }

    void pop_front(char *s, const char *e) /// # O(len)
    {
        while(s!=e)
        {
            pop_front(*s);
            s++;
        }
    }

    void pop_front(const Hash &A) /// # O(1)
    {
        S -= A.S;
        val1 -= A.val1 * C1[S];
        val1 = (val1%mod1+mod1)%mod1;
        val2 -= A.val2 * C2[S];
        val2 = (val2%mod2+mod2)%mod2;
    }

    void operator-=(const Hash &A) /// # O(1)
    {
        pop_back(A);
    }

    void operator-=(const char &x) /// # O(1)
    {
        pop_back(x);
    }

    void operator-=(const string &s) /// # O(len)
    {
        pop_back(s);
    }

    void operator=(const char &s) /// # O(1)
    {
        val1 = (long long int)s;
        val2 = (long long int)s;
        S = 1LL;
    }

    void operator=(const string &s) /// # O(len)
    {
        clear();
        push_back(s);
    }

    void operator=(const Hash &A) /// # O(1)
    {
        val1 = A.val1;
        val2 = A.val2;
        S = A.S;
    }

    bool operator==(const Hash &A) const /// # O(1)
    {
        return (val1 == A.val1 && val2 == A.val2 && S == A.S);
    }

    bool operator==(const string &s) const /// # O(len)
    {
        Hash A(s);
        return (val1 == A.val1 && val2 == A.val2 && S == A.S);
    }

    bool operator==(const char &x) const /// # O(1)
    {
        return (val1 == (long long int)x && val2 == (long long int)x && S == 1);
    }

    bool empty() /// # O(1)
    {
        return (S == 0);
    }

    long long int size() /// # O(1)
    {
        return S;
    }
}EMPTY, PLUS, MINUS;

template <typename T>
Hash operator+(const Hash &A, const T &B)
{
    PLUS = A;
    PLUS += B;
    return PLUS;
}

template <typename T>
Hash operator-(const Hash &A, const T &B)
{
    MINUS = A;
    MINUS -= B;
    return MINUS;
}
int main()
{

    return 0;
}


you can push_back, pop_back, push_front, pop_front a char*, string ,a char and also a hash to your hash and many other work. notice mainly when you want to use a string or a char* program handle on O(length) but when you use hash or a char it will be O(1). and also for the first time you want to hash some thing program does Preprocessing in O(MAX_Hash) where MAX_Hash is max length of a string you want to hash it, you can easily set it. its default is 1e6 + 5.

For the theory part you can visit : https://cp-algorithms.com/string/string-hashing.html

about variable I use: S is length of hashed string, val1 is hash of string in mod mod1, val2 is hash of string in mod mod2. note : there is no Anti-hash yet that can hack you with this hash function.

Now I want to introduce functions one by one in examples:

    char t[20] = "Hash Struct . . .";
    string s = "OK!";
    Hash A; /// simple
    Hash B("Hello codeforces !"); /// give a string
    Hash C(t,t+17); /// give a char* with two pointers
    Hash D(B); /// give an other Hash

    B.clear(); /// now B is completely empty

    D.push_back('@'); /// -@- will added to end of D
    B.push_back(s); /// string s will added to end of B
    B.push_back(t,t+4); /// -Hash- (t,t+4) will added to end of B
    C.push_back(A); /// A will added to C but A was empty and has no effect

    D.push_front('_'); /// -_ will added to front of D
    B.push_front("String B is :"); /// -String B is :- will added to front of B
    A.push_front(t+5,t+12); /// -Struct - (t+5,t+12) will added to front of A
    C.push_front(A); /// A will added to front of C

    B += D; /// D will added to end of B
    A += '%'; /// -%- will added to end of A
    C += "I am C !"; /// -I am C !- will added to end of C

    /*
        notice pop_back and pop_front should give a real char, string, char* or a Hash
        for example A is "Struct" now and we can:
    */
    A.pop_back('t'); /// -Struct- -> -Struc-
    A.pop_back("uc"); /// -Struc- -> -Str-
    A.pop_back(t+7,t+8); /// -Str- -> -St-
    A.pop_back(A); /// It's unusual way to clear a Hash !

    /// B's front is -String B is :-
    B.pop_front("String"); /// -String B is :- -> - B is :-
    B.pop_front(' '); /// - B is :- -> -B is :-
    B.pop_front(t+4,t+4); /// nothing
    B.pop_front(B); /// It's unusual way to clear a Hash !

    /// -= is like pop_back so now C has -I am C !- at end
    C -= '!'; /// -I am C !- -> -I am C -
    C -= " C "; /// -I am C - -> -I am-
    C -= C; /// C now is empty but if for example Hash E = " am", you can write C -= E => -I am- -> -I-

    D = '*'; /// now D is just -*-
    A = "ABCD"; /// now A is just -ABCD-
    B = A; /// now B is just like A means -ABCD- here

    A == B; /// return true if A is_equal to B else false
    D == "ABDE"; /// return true if A is_equal to -ABDE- else false
    D == '*'; /// return true if D = -*- else false

    C.empty(); /// return true if and just if length of C is 0
    C.size(); /// return length of C

    D = A + B - C; /// D will be A + B - C(it's different from A - C + B)

At last If you have a suggestion or want to know something or find a bug(you can't find bug but maybe) or else please and please tell me by writing comments.

Hope to enjoy it.

THE END . . .

Tags #string-hashing, #hashing, #string, #string matching, #data structures, #substring-hash

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en3 English MohammadParsaElahimanesh 2021-03-17 11:32:23 5 Tiny change: 'ue if and if length' -> 'ue if and just if length'
en2 English MohammadParsaElahimanesh 2021-02-06 16:09:15 0 (published)
en1 English MohammadParsaElahimanesh 2021-02-06 16:08:18 10378 Initial revision (saved to drafts)