Hash structure of data structure and algorithm (biased to JS)

Posted by ilikemath2002 on Fri, 19 Jun 2020 06:02:34 +0200

Data structure (4)

Note: This paper is based on the collation of BiliBili Video [JavaScript data structure and algorithm]

hash table

  1. Its structure is an array. It converts hashcode into an array's subscript through a hash function

  2. Features: compared with array, advantages: insert, query and delete operations are very efficient; disadvantages: disorder, can not be repeated, space utilization is not high;

  3. Related concepts

    • Hashing: the process of converting a large number into an array range subscript (remainder operation);

    • Hash function: the word is converted into a large number hashcode (multiplication and addition of power, avoiding repetition), and the code of hashing the large number is encapsulated in a function;

    • Goal of a good hash function:

      • Fast, (Horner's Law: multiplication and addition of powers, optimization of polynomials): Pn(x)= anx n+a(n-1)x(n-1) + +a1x+a0=((… (((anx +an-1)x+an-2)x+ an-3)… )x+a1)x+a0
      • Uniform distribution of subscripts: where constants are used, try to use prime numbers, such as the length of hash table and the base of power N (we used 27 before)
    • Hash table: finally insert data into this array, encapsulate the whole structure, called a hash table

    • Fill factor: the ratio of the total data items to the total length of the hash table. The smaller the filling factor, the lower the storage efficiency and the faster the detection speed

    • matters needing attention

    1. When the remainder operation is repeated, but the hash table cannot be repeated, the solution to this conflict is as follows:
      • Efficiency ranking of hashing: 1 ️⃣ Two ️⃣ Three ️⃣ Four ️⃣
      • Chain address method (zipper method): store an array or linked list in the hashed array unit (according to business requirements: array for searching and linked list for others); first find the location through array subscript, and then operate in the linked list or array. One ️⃣
      • Open address method: look for blank cells to add new elements. The methods are:
        • On the basis of linear search, the step size is dealt with; x,x+12,x+22 2 ️⃣
        • For linear search, the subscript cannot be set to null when deleting, because it will be specially processed and can be - 1; x,x+1,x+2 4 ️⃣
        • Again hashing method; depending on the keyword, hashing the keyword as the step size of the previous hash function; the hashing result is different from the first time, and cannot be 0. [stepsize = constant - (key% constant), never 0] 3 ️⃣
  4. Implementation method: Based on array ()

  5. Common operations
    -put insert or modify
    - get
    - remove
    -Capacity prime
    -Other: isEmpty, size

Code of relevant operation:

  • hash function
// Hash function: a function that converts the name key to a subscript value
        // Convert to larger number: hashcode
        // Move hashcode to array range (size)
        function hashFunc(str, size) {
            var hashcode = 0;
            for (let i = 0; i < str.length; i++) {
            // The base number is prime 31, 37, etc
                hashcode = 37 * hashcode + str.charCodeAt(i);
                console.log(hashcode, str[i], i);

            }
            index = hashcode % 7;
            return index
        }
        // console.log('aa'.charCodeAt(0));
        // hashFunc('cc', 7)
        console.log(hashFunc('22', 11)); //4
        console.log(hashFunc('32', 11)); // 1
        console.log(hashFunc('34', 11)); // 2
  • Judge prime number
        // Efficient judgment: high efficiency of square root

        // A number, two numbers after factoring, one must be smaller than the number after square root, and one larger than square root. Since the small square root hasn't been divided, the big one can't be divided
        //  A number between 16 = 2 * 8, 4 * 4 = 16 1-4 is divided by an integer, not a prime number
        //   17 = 1 * 17, 4.12 * 4.12 = = 17 before 4.12, no number can be divided, so it is a prime number
        function isPrimeSqrt(num) {
            if (num == 0 || num == 1) {
                return false
            }
            const temp = parseInt(Math.sqrt(num));
            for (let i = 2; i <= temp; i++) {
                if (num % 2 == 0) {
                    return false;
                }
            }
            return true;
        }

  • Hashtable
        // Hashtable 
        // Hashing with chain address method   
        // The final deconstruction of table structure [[[key, Val], [key, Val], [key, Val], [key, Val], [key, Val], [key, Val],]
        function HashTable() {
            // attribute
            this.storage = []; //storage space 
            this.count = 0; // Record current data length
            this.limit = 3; //The capacity of the table should be prime
            // Make the capacity constant to Prime: after double expansion, it must not be prime. You can add one to double each time to judge whether it is prime or not

            this.loadFactor = this.count / this.limit; //Double the capacity if filling factor > 0.75
            // method

            // hash function 
            HashTable.prototype.hashFunc = function(str, size) {
                var hashcode = 0;
                // Horner's law, turn it into a large number, hashcode
                for (var i = 0; i < str.length; i++) {
                    // 37, 31, 41, etc
                    hashcode = 37 * hashcode + str.charCodeAt(i);
                    // console.log(hashcode, str[i], i);
                }
                // Take remainder, return subscript
                index = hashcode % size;
                return index;
            };

            // Insert and modify data
            // Parameter: key: for example, a name, value: for example, the identity information corresponding to the name
            HashTable.prototype.put = function(key, value) {
                // Find the location of the index according to the key,
                var index = this.hashFunc(key, this.limit);
                // Find the element bucket placed in this position according to the index, which should be an array
                var bucket = this.storage[index];
                //Judge whether the bucket is null. If it is null, create it. Assign the element as an array, and then place the array element in this location
                if (bucket === undefined) {
                    bucket = [];
                    this.storage[index] = bucket;
                }
                // console.log(bucket, this.count);

                // Determine whether the key exists in the bucket,
                // Modify if existing
                var override = false;
                for (var i = 0; i < bucket.length; i++) {
                    var tuple = bucket[i];

                    if (tuple[0] == key) {
                        tuple[1] = value;
                        override = true;
                        return;
                    }
                }
                // Add if not
                if (!override) {
                    bucket.push([key, value]);
                    this.count++;
                    //   Expansion
                    if (this.count > this.limit * 0.75) {
                        var size = this.limit * 2;
                        var newPrimeSize = this.turnPrime(size);
                        this.resize(newPrimeSize);
                    }
                }
            };

            // obtain
            HashTable.prototype.get = function(key) {
                var index = this.hashFunc(key, this.limit);
                var bucket = this.storage[index];

                if (bucket == null || bucket == undefined) {
                    return null;
                }
                // Linear search bucket
                if (bucket) {
                    for (var i = 0; i < bucket.length; i++) {
                        const tuple = bucket[i];
                        if (tuple[0] === key) {
                            return tuple[1];
                        }
                    }
                    return null;
                }
            };
            // delete
            HashTable.prototype.remove = function(key) {
                var index = this.hashFunc(key, this.limit);
                var bucket = this.storage[index];
                if (bucket == null) {
                    return null;
                }
                for (var i = 0; i < bucket.length; i++) {
                    const tuple = bucket[i];
                    if (tuple[0] == key) {
                        bucket.splice(i, 1);
                        this.count -= 1;

                        //   Reduce capacity
                        // Avoid being too small
                        if (this.limit > 7 && this.count < this.limit * 0.25) {
                            var size = Math.floor(this.limit / 2);
                            var newPrimeSize = this.turnPrime(size);
                            this.resize(newPrimeSize);
                        }
                        return tuple[1];
                    }
                }
                return null;
            };

            // isEmpty,size
            HashTable.prototype.isEmpty = function() {
                return this.count == 0;
            };
            HashTable.prototype.size = function() {
                return this.count;
            };

            // Hash table expansion
            HashTable.prototype.resize = function(newlimit) {
                var oldStorage = this.storage;
                this.storage = [];
                this.count = 0;
                this.limit = newlimit;
                for (let i = 0; i < oldStorage.length; i++) {
                    const bucket = oldStorage[i];

                    if (bucket == null) {
                        continue;
                    }
                    for (let j = 0; j < bucket.length; j++) {
                        const tuple = bucket[j];
                        this.put(tuple[0], tuple[1]);
                    }
                }
            };

            // Judge whether it is a prime number
            HashTable.prototype.isPrime = function(num) {
                if (num == 0 || num == 1) {
                    return false;
                }
                const temp = parseInt(Math.sqrt(num));
                for (let i = 2; i <= temp; i++) {
                    if (num % 2 == 0) {
                        return false;
                    }
                }
                return true;
            }

            // Convert to prime
            HashTable.prototype.turnPrime = function(num) {
                // Add one to num at a time until you find prime
                while (!this.isPrime(num)) {
                    num++;
                }
                return num;
            };
        }
        const tabs = new HashTable();
        tabs.put("age", 12);
        tabs.put("name", "wei");
        tabs.put("sex", "man");
        tabs.put("sex1", "man");

        console.log(tabs.get("age"), "table");
        console.log(tabs.limit, 'limit');

        tabs.put("name", "sss");
        console.log(tabs.get("name"), "modify");
        //
        tabs.remove("name");
        console.log(tabs.get("name"), "remove");

Other data structures can access the following addresses:

Data structure and algorithm (1): array, queue, stack (JS oriented)
Data structure and algorithm (2): one way linked list and two way linked list (biased JS)
Set of data structure and algorithm (3), dictionary

Topics: Javascript Attribute