Método de presupuesto de estructura de datos Python implementa una tabla hash

Tabla de picadillo

Para localizar rápidamente un elemento, el científico le da a cada elemento un "subíndice lógico" y luego lo encuentra directamente. La tabla hash es una implementación de este tipo. Utiliza una función hash para calcular dónde debe colocarse un elemento. Por supuesto Para un elemento específico, el subíndice calculado por la función hash debe ser el mismo cada vez y el rango no puede exceder la longitud de la matriz dada.
Si tenemos una matriz t que contiene m = 13 elementos, podemos definir una función hash simple h (clave) = clave% m donde la función de módulo hace que el resultado de h (clave) no exceda el subíndice de la longitud de la matriz, inserte el siguientes elementos 756, 431, 142, 579, 226, 903, 338
Conflictos de hash: después del cálculo del algoritmo de hash, se produce un conflicto de subíndice. El valor actual debajo del subíndice tendrá un enlace al valor en conflicto (método de enlace). Desventajas, si hay más conflictos, la complejidad temporal de la búsqueda no es O (1).
También existe un método de direccionamiento abierto: su idea básica es utilizar una forma de encontrar el siguiente intervalo cuando un intervalo está ocupado, de acuerdo con la búsqueda del siguiente slot Los métodos son diferentes, divididos en:
sonda lineal: cuando la ranura está ocupada, encuentra la siguiente ranura disponible.
Sonda secundaria: cuando la ranura está ocupada, usa la segunda como el desplazamiento.
Doble hash: recalcula el resultado de hash.
Python usa el segundo método de sondeo, esto significa que si hay un conflicto, vamos a aumentar la i-
cuadrado
factor de carga a la posición original. Factor de carga:. el número de ranuras que se han utilizado es mayor que el número total de ranuras
Cuando el el espacio no es suficiente, definimos un factor de carga Concepto, como insertar 8 elementos, el número total de ranuras es 13, es decir, 8/13 es aproximadamente igual a 0,62. En general, cuando el factor de carga es menor que 0.8, es necesario abrir un nuevo espacio, y volver a aplicar
el hash rojo
cuando el factor de carga es menor a 0.8, reabrirá el espacio, la estrategia de espacio abierto depende de la implementación subyacente específica, no después del Re-hash de los datos de la ranura vacía en la tabla,
simule cpython para implementar una tabla hash
Las tres operaciones más comúnmente utilizadas, agregar, obtener y eliminar
ranuras, generalmente tienen tres estados:
nunca usado: HashMap.UNUSED se ha usado
pero eliminado : HashMap.EMPTY
está usando el nodo

class Array(object):

    def __init__(self,size=32,inits=None):
       self._size = size
       self._items = inits* size

    def __getitem__(self,index):
        return self._items[index]

    def __setitem__(self,index,value):
        self._items[index] = value

    def __len__(self):
        return self._size

    def clear(self,value = None):
        for i in range(self._items):
            self._items[i] = value

    def __iter__(self):
        for item in self._items:
            yield item

#定义一个槽
class Slot(object):
    """
    定义一个哈希表数组的槽
    注意,一个槽有三种状态,看你能否想明白,相比链接法解决冲突,二次探查法删除一个key更加复杂
    1.从未使用 HashMap.UNUSED.次槽没有被使用和冲突过,查找时只要找到UNUSED就不用再继续探查了
    2.使用过但是remove了,此时hashMpa.BMPTY,该探查点后边的元素仍可是key
    3.槽正在使用Slot点
    """

    def __init__(self,key,value):
        self.key,self.value = key,value


#实现哈希表
class HashTable(object):
    UNUSED = None #没被使用过
    BMPTY = Slot(None,None)#使用过但是删除了

    #初始化函数
    def __init__(self):
        #定义一个数组
        self._table = Array(8,init = HashTable.UNUSED)
        #插入了多少个值
        self.length = 0

    #装饰器,用于计算装载因子
    @property
    def _load_factor(self):
        return self.length / float(len(self._table))

    #hash表的长度
    def __len__(self):
        return self.lenght

    #hsah函数 根据key得到一个数组的下标
    def _hash(self,key):
        #abs返回绝对值 hash返回key的hash值
        return abs(hash(key)) % len(self._table)

    #寻找key
    def _find_key(self,key):
        #调用哈希函数,得到第一个槽的位置
        index = self._hash(key)
        #hash表的长度
        _len = len(self._table)
        #表中槽的init值是否为HashMapp.UNUSED
        while self._table[index] is not HashTable.UNUSED:
            #表中槽的init是否为HashMap.EMPTY
            if self._table[index] is HashTable.EMPTY:
                #重新计算key
                index = (index * 5 + 1) % _len
                #跳过出此次循环
                continue
            #表中有这个key直接输出key
            elif self._table[index].key == key:
                return index
            #否则重新计算key
            else:
                index = (index * 5 + 1) % _len
        #返回None
        return None
    #判断槽能不能被插入
    def _silot_con_insert(self,index):
        return (self._table[index] is HashTable.BMPTY or self._table[index] is HashTable.UNUSED)

    #找到一个空槽的位置
    def _find_slot_for_insert(self,key):
        #获取k的哈希值
        index = self._hash(key)
        #获取到hash表的长度
        _len = len(self._table)
        #如果不能插入,就重新定义key
        while not self._slot_for_insert(index):
            index = (index * 5 + 1) % _len
        return index
    #添加键值对
    def add(self,key,value):

        if key in self:
            #如果有就找到key
            index = self._find_key(key)
            #把value赋值给槽
            self._table[index].value = value
            return False
        else:
            #如果没有找到一个空槽的key
            index = self._find_slot_for_insert(key)
            #这个空槽指向新的槽
            self._table[index] = Slot(key,value)
            #长度加一
            self.length += 1
            #计算装载因子
            if self._load_factor >= 0.8:
                self._rehash()
            return True

    #装载因子小于0.8
    def _rehash(self):
        #把原来的表,赋值给old_table
        old_table = self._table
        #原来的长度剩2,赋值给newsize
        newsize = len(self._table)*2
        #新建一个数组
        self._table = Array(newsize,HashTable.UNUSED)
        self.length = 0
        #遍历原来的数组
        for slot in old_table:
            #判断是否有值
            if slot is not HashTable.UNUSED and slot is not HashTable.BMPTY:
                #找到新key,赋值给index
                index = self._find_slot_for_insert(slot.key)
                #slot赋值到槽中
                self._table[index] = slot
                #长度加一
                self.length += 1
    #取值操作
    def get(self,key,default=None):
        #找到这个key
        index = self._find_key(key)
        #key如果是和None
        if index is None:
            #返回None
            return default
        else:
            #否则槽中value
            return self._table[index].value
    #删除操作
    def remove(self,key):
        #找到key
        index = self._find_key(key)
        #key为None就抛出异常
        if index is None:
            raise KeyError()
        #取到槽中的value
        value = self._table[index].value
        #长度减一
        self.length -=1
        #赋值给key一个状态
        self._table[index] = HashTable.BMPTY
        #赶回值
        return value
    #遍历
    def __iter__(self):
        #循环数组
        for slot in self._table:
            #判断状态
            if slot not in (HashTable.BMPTY,HashTable.UNUSED):
                #生成值
                yield slot.key

Supongo que te gusta

Origin blog.csdn.net/weixin_44865158/article/details/100777969
Recomendado
Clasificación