Esempio n. 1
0
    def delete(self, elm):
        """
        Deletes existing items in the table and handles possibility that
        collisions have occurred.

        :param elm: the element to delete
        :return: the probe count if deleted, else error
        """
        k = hashcode(elm, self.buckets)
        ctr = 1

        while ctr <= self.buckets:
            if not self.__ht[k]:
                raise HashSearchException(f"{elm} does not exist.")

            # Remove
            if self.__ht[k] == elm and not self.__ht_d[k]:
                # TODO: Set to None as well?
                self.__ht_d[k] = True
                return ctr

            # Collision
            k = self.__probe(k)  # find next address
            ctr += 1

        raise HashSearchException(f"Could not delete {elm} on probing.")
Esempio n. 2
0
    def search(self, elm):
        """
        SEARCH-003
        Hash based search using open addressing.

        Average: O(1)
        Worst: O(n)
        Best: O(1)

        :param elm: element to find
        :return: True if found, else False
        """
        k = hashcode(elm, self.buckets)
        ctr = 1

        while ctr <= self.buckets:
            if self.__ht[k] is None:
                return False

            if self.__ht[k] == elm and not self.__ht_d[k]:
                return True

            # Collision
            k = self.__probe(k)  # find next address
            ctr += 1

        return False
Esempio n. 3
0
def hash_search(arr, elm, buckets=2**9 - 1):
    """
    SEARCH-002
    In Hash-Based Search the n elements of a collection C are first
    loaded into a hash table H with b bins structured as an array.
    This pre-processing step has O(n) performance. Once all elements
    have been inserted, searching for an item t becomes a search for
    t within H[hash(t)].

    The size of H is typically chosen to be a prime number to ensure
    that using the % modulo operator efficiently distributes the
    computed bin numbers (2**k - 1).

    Average: O(1)
    Worst: O(n)
    Best: O(1)

    :param arr: input List
    :param elm: element to find in arr
    :param buckets: number of buckets to use in hashtable
    :return: True if found, else False
    """
    ht = __build_table_list(buckets, arr)
    bucket = ht[hashcode(elm, buckets)]

    if bucket and elm in bucket:
        return True

    return False
Esempio n. 4
0
def __build_table_list(buckets, arr):
    """
    Uses list to handle collisions. Open addressing is a variation
    which does not require additional linked list storage.

    :param buckets: the number of buckets
    :param arr: the input array
    :return: List of sz empty buckets
    """
    from collections import defaultdict

    ht = defaultdict(list)

    for elm in arr:
        hc = hashcode(elm, buckets)
        ht[hc].append(elm)

    return ht
Esempio n. 5
0
    def add(self, elm):
        """

        :param elm: the element to add
        :return: the probe count if added, else error
        """
        k = hashcode(elm, self.buckets)
        ctr = 1

        while ctr <= self.buckets:
            if self.__ht[k] is None or self.__ht_d[k]:
                self.__ht[k] = elm
                self.__ht_d[k] = False
                return ctr

            # Already there
            if self.__ht[k] == elm and not self.__ht_d[k]:
                return ctr

            # Collision - something else is there
            k = self.__probe(k)  # find next address
            ctr += 1

        raise HashSearchException(f"Could not add {elm} on probing.")