85 lines
5.7 KiB
Markdown
85 lines
5.7 KiB
Markdown
|
## Домашнее задание №4 «LRU-кэш»
|
|||
|
Необходимо реализовать LRU-кэш на основе двусвязного списка.
|
|||
|
|
|||
|
Задание состоит из двух частей, которые необходимо выполнять последовательно.
|
|||
|
|
|||
|
### 1) Реализация двусвязного списка
|
|||
|
Список имеет структуру вида
|
|||
|
```text
|
|||
|
nil <- (prev) front <-> ... <-> elem <-> ... <-> back (next) -> nil
|
|||
|
```
|
|||
|
|
|||
|
Необходимо реализовать следующий интерфейс List:
|
|||
|
- Len() int // длина списка
|
|||
|
- Front() *ListItem // первый элемент списка
|
|||
|
- Back() *ListItem // последний элемент списка
|
|||
|
- PushFront(v interface{}) *ListItem // добавить значение в начало
|
|||
|
- PushBack(v interface{}) *ListItem // добавить значение в конец
|
|||
|
- Remove(i *ListItem) // удалить элемент
|
|||
|
- MoveToFront(i *ListItem) // переместить элемент в начало
|
|||
|
|
|||
|
**Считаем, что методы Remove и MoveToFront вызываются только от существующих в списке элементов.**
|
|||
|
|
|||
|
Элемент списка ListItem:
|
|||
|
- Value interface{} // значение
|
|||
|
- Next *ListItem // следующий элемент
|
|||
|
- Prev *ListItem // предыдущий элемент
|
|||
|
|
|||
|
Сложность всех операций должна быть O(1),
|
|||
|
т.е. не должно быть мест, где осуществляется полный обход списка.
|
|||
|
|
|||
|
### 2) Реализация кэша на основе ранее написанного списка
|
|||
|
Необходимо реализовать следующий интерфейс Cache:
|
|||
|
- Set(key Key, value interface{}) bool // Добавить значение в кэш по ключу.
|
|||
|
- Get(key Key) (interface{}, bool) // Получить значение из кэша по ключу.
|
|||
|
- Clear() // Очистить кэш.
|
|||
|
|
|||
|
Структура кэша:
|
|||
|
- ёмкость (количество сохраняемых в кэше элементов)
|
|||
|
- очередь \[последних используемых элементов\] на основе двусвязного списка
|
|||
|
- словарь, отображающий ключ (строка) на элемент очереди
|
|||
|
|
|||
|
Элемент кэша хранит в себе ключ, по которому он лежит в словаре, и само значение.
|
|||
|
Для чего это нужно понятно из алгоритма работы кэша (см. ниже).
|
|||
|
|
|||
|
Сложность операций `Set`/`Get` должна быть O(1), при желании `Clear` тоже можно сделать О(1).
|
|||
|
|
|||
|
Алгоритм работы кэша:
|
|||
|
- при добавлении элемента:
|
|||
|
- если элемент присутствует в словаре, то обновить его значение и переместить элемент в начало очереди;
|
|||
|
- если элемента нет в словаре, то добавить в словарь и в начало очереди
|
|||
|
(при этом, если размер очереди больше ёмкости кэша,
|
|||
|
то необходимо удалить последний элемент из очереди и его значение из словаря);
|
|||
|
- возвращаемое значение - флаг, присутствовал ли элемент в кэше.
|
|||
|
- при получении элемента:
|
|||
|
- если элемент присутствует в словаре, то переместить элемент в начало очереди и вернуть его значение и true;
|
|||
|
- если элемента нет в словаре, то вернуть nil и false
|
|||
|
(работа с кешом похожа на работу с `map`)
|
|||
|
|
|||
|
Ожидаются следующие тесты:
|
|||
|
- на логику выталкивания элементов из-за размера очереди
|
|||
|
(например: n = 3, добавили 4 элемента - 1й из кэша вытолкнулся);
|
|||
|
- на логику выталкивания давно используемых элементов
|
|||
|
(например: n = 3, добавили 3 элемента, обратились несколько раз к разным элементам:
|
|||
|
изменили значение, получили значение и пр. - добавили 4й элемент,
|
|||
|
из первой тройки вытолкнется тот элемент, что был затронут наиболее давно).
|
|||
|
|
|||
|
**(*) Дополнительное задание: сделать кэш горутино-безопасным.**
|
|||
|
|
|||
|
### Критерии оценки
|
|||
|
- Пайплайн зелёный - 4 балла
|
|||
|
- Добавлены новые юнит-тесты для списка - 1 балл
|
|||
|
- Добавлены новые юнит-тесты для кэша (см. выше) - до 3 баллов
|
|||
|
- Понятность и чистота кода - до 2 баллов
|
|||
|
- Дополнительное задание на баллы не влияет
|
|||
|
|
|||
|
#### Зачёт от 7 баллов
|
|||
|
|
|||
|
### Подсказки
|
|||
|
- https://en.wikipedia.org/wiki/Doubly_linked_list
|
|||
|
- https://ru.bmstu.wiki/LRU_(Least_Recently_Used)
|
|||
|
- `sync.Mutex`
|
|||
|
|
|||
|
### Частые ошибки
|
|||
|
1) В задании со звёздочкой забывают про синхронизацию в методе Clear кэша.
|