El algoritmo LRU en realidad le permite diseñar la estructura de datos: primero necesita recibir un parámetro de capacidad como la capacidad máxima de la memoria caché, y luego implementar dos API, uno es el método put (clave, val) para almacenar pares clave-valor, y el otro es obtener (clave ) El método obtiene el valor correspondiente a la clave y devuelve -1 si la clave no existe.
Tenga en cuenta que los métodos get y put deben tener una complejidad de tiempo O (1), tomemos un ejemplo específico para ver cómo funciona el algoritmo LRU.
/ * La capacidad de la caché es 2 * / LRUCache cache = new LRUCache (2 ); // Puedes entender la caché como una cola // Suponiendo que la izquierda es la cabeza del equipo, y la derecha es la cola del equipo /// La cola utilizada más recientemente está en la cabeza de la cola , mucho tiempo Utilizado al final de la línea // los paréntesis indican pares clave-valor (clave, val) cache.put ( 1, 1 ); // caché = [(1, 1 )] cache.put ( 2, 2 ); // cache = [(2, 2), (1, 1 )] cache.get ( 1); // devuelve 1 // cache = [(1, 1), (2, 2 )] // explicación: debido al acceso reciente La clave 1 se ha ido , así que avance a la cabecera de la cola // devuelva el valor correspondiente a la clave 1 1 cache.put ( 3, 3 ); // cache = [(3, 3), (1, 1 )] // Explique: capacidad de caché Completo, necesita eliminar contenido para hacer espacio // Prioridad eliminar los datos que no se han utilizado durante mucho tiempo, es decir, los datos al final del equipo // y luego insertar los nuevos datos en el encabezado de la cola cache.get ( 2); // devuelve -1 (no encontrado) // caché = [(3, 3 ), (1, 1 )] // Explicación: No hay datos con la clave 2 en caché cache.put ( 1, 4 ); // caché = [(1, 4), (3, 3 )] // Explicación : La clave 1 ya existe, sobrescribe el valor original 1 a 4 // No olvides llevar el par clave-valor a la cabeza del equipo
Analizando el proceso de operación anterior, para hacer la complejidad temporal de los métodos de poner y obtener O (1), podemos resumir las condiciones necesarias de la estructura de datos de caché: búsqueda rápida, inserción rápida, eliminación rápida, en orden.
Debido a que está claro que la memoria caché debe ordenarse para distinguir los datos utilizados más recientemente y los que se usaron durante mucho tiempo; y debemos encontrar si la clave ya existe en la memoria caché; si la capacidad está llena, debemos eliminar los últimos datos; cada vez que tengamos que insertar los datos A la cabeza del equipo.
Entonces, ¿qué estructura de datos cumple las condiciones anteriores al mismo tiempo? La búsqueda en la tabla hash es rápida, pero los datos no tienen un orden fijo; las listas vinculadas tienen orden, la inserción y eliminación son rápidas, pero la búsqueda es lenta. Entonces combínelos para formar una nueva estructura de datos: lista enlazada hash.
La estructura central de datos del algoritmo de caché LRU es una combinación de listas enlazadas hash, listas doblemente enlazadas y tablas hash. Esta estructura de datos se ve así:
Se requiere la operación de eliminación. La eliminación de un nodo no solo requiere el puntero del nodo en sí, sino que también debe operar el puntero de su nodo predecesor, y la lista doblemente vinculada puede admitir la búsqueda directa del predecesor, asegurando la complejidad temporal de la operación O (1).
'' ' Método uno clase LRUCache: # @ capacidad param, un entero def __init __ (self, capacidad): self.cache = () self.used_list = [] self.capacity = capacidad # @ devuelve un entero def get (self, clave): si la clave en self.cache: #Utilice una lista para registrar el orden de acceso, el primero en acceder se coloca delante de la lista y el último en acceder se coloca detrás de la lista, por lo que cuando el caché esté lleno, elimine la lista [0 ], Y luego inserte un nuevo elemento; si key! = Self.used_list [-1]: self.used_list.remove (key) self.used_list.append (key) return self.cache [key] else: return -1 def put ( self, key, value): si ingresa self.cache: self.used_list.remove (key) elif len (self.cache) == self.capacity: self.cache.pop (self.used_list.pop (0)) self.used_list.append (key) self.cache [clave] valor = '' ' # Segundo método: Importar Colecciones # orderedDict implementado con base de clase del LRUCache (collections.OrderedDict): ' '' función: tipo de datos utilizando un algoritmo collection.OrdereDict menos usado recientemente OrdereDict tiene un método especial popitem (Últimos = Cuando es falso), se implementa la cola y se abre el primer elemento insertado . Cuando Last = True, se implementa el método de pila y se abre el último elemento insertado. Se implementan dos métodos: get (key) extrae el valor correspondiente en la clave, si no devuelve None set (key, value), tiene más características de LRU y agrega elementos '' ' def __init__ (self, size = 5): Self.size = tamaño self.cache = collections.OrderedDict () # ordenó diccionario DEF GET (Ser, Key): SI clave en self.cache.keys (): # porque también grabó en la visita de visita vez (por orden) valor = self.cache.pop (clave) # garantía de la reciente visita de la lista está siempre en la superficie final self.cache [Key] = valor de retorno valor de la persona : valor = Ninguno de retorno valor DEF PUT (Ser, clave, valor ): siclave en self.cache.keys (): self.cache.pop (key) self.cache [key] = value elif self.size == len (self.cache): self.cache.popitem (last = False) self .cache [clave] = valor más : self.cache [clave] = valor si __name__ == ' __main__ ' : test = LRUCache () test.put ( ' a ' , 1 ) test.put ( 'b ' , 2 ) test.put ( ' c ' , 3 ) test.put ( ' d ' , 4 ) test.put ( ' e ' , 5 ) # test.put (' f ', 6) print (prueba. obtener ( ' a ' ))
Referencia: https://blog.csdn.net/qq_35810838/article/details/83035759
https://labuladong.gitbook.io/algo/gao-pin-mian-shi-xi-lie/lru-suan-fa