Алгоритмы и структуры данных меняющие современный Frontend
XBSoftware
Вопросы на сегодня:
- Для чего фронтенд программисту нужно знать структуры данных и алгоритмы?
Типы деревьев:
- Красно-чёрное дерево
- Куча
- Префиксное дерево
- B-дерево
- R-дерево
- АВЛ-дерево
- и другие
Операция |
Сложность |
Метод |
Добавление |
O(1) |
insertBefore, appendChild, append, prepend, after, before |
Удаление |
O(1) |
removeChild, remove, replaceWith |
Поиск |
O(1)/O(n) |
querySelector, querySelectorAll, getElementById, getElementsByClassName |
Поиск по DOM дереву:
- Поиск в ширину
- Поиск в глубину
Поиск в ширину:
Поиск в глубину:
Старое дерево |
Новое дерево |
<li>Первый</li> |
<li>Первый</li> |
<li>Второй</li> |
<li>Третий</li> |
<li>Третий</li> |
|
Старое дерево |
Новое дерево |
<li>Первый</li> |
<li>Первый</li> |
<li>Второй</li> |
<li>Третий</li> |
<li>Третий</li> |
|
Старое дерево |
Новое дерево |
Результат |
<li>Первый</li> |
<li>Первый</li> |
<li>Первый</li> |
<li>Второй</li> |
<li>Третий</li> |
|
<li>Третий</li> |
|
|
Старое дерево |
Новое дерево |
Результат |
<li>Первый</li> |
<li>Первый</li> |
<li>Первый</li> |
<li>Второй</li> |
<li>Третий</li> |
<li>Третий</li> |
<li>Третий</li> |
|
|
Старое дерево |
Новое дерево |
Результат |
<li>Первый</li> |
<li>Первый</li> |
<li>Первый</li> |
<li>Второй</li> |
<li>Третий</li> |
<li>Третий</li> |
<li>Третий</li> |
|
<li>Третий</li> |
Старое дерево |
Новое дерево |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
|
Старое дерево |
Новое дерево |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
|
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
Старое дерево |
Новое дерево |
Результат |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
|
<li key="key3">Третий</li> |
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
Старое дерево |
Новое дерево |
Результат |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
|
<li key="key3">Третий</li> |
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
Старое дерево |
Новое дерево |
Результат |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
|
<li key="key3">Третий</li> |
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
Старое дерево |
Новое дерево |
Результат |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
|
<li key="key3">Третий</li> |
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
Старое дерево |
Новое дерево |
Результат |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
|
<li key="key2">Второй</li> |
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
Старое дерево |
Новое дерево |
Результат |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
|
<li key="key2">Второй</li> |
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
Старое дерево |
Новое дерево |
Результат |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key1">Первый</li> |
<li key="key2">Второй</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
<li key="key3">Третий</li> |
|
<li key="key2">Второй</li> |
Хэш-таблица
Ключ |
Компонент |
key1 |
<li key="key1">Первый</li> |
key2 |
<li key="key2">Второй</li> |
key3 |
<li key="key3">Третий</li> |
lit-html
const render = () => html`
<ul>
${repeat(items, i => i.key, (i, index) => html`
<li>${index}: ${i.name}</li>`)}
</ul>
`;
Где ещё используются деревья:
- Специфические доменные области
- AST (abstract syntax tree)
- Файловая структура
- Неизменяемые данные
var arr = ["a", "b", "c", "z", "f", "k"];
function render(items) {
return arr
.map(item => `<div>${ item }</div>`)
.join(", ");
}
nav.innerHTML = render(arr.sort());
div.innerHTML = render(arr);
var arr = ["a", "b", "c", "z", "f", "k"];
function render(items) {
return arr
.map(item => `<div>${ item }</div>`)
.join(", ");
}
nav.innerHTML = render(arr.sort());
div.innerHTML = render(arr);
var arr = ["a", "b", "c", "z", "f", "k"];
function render(items) {
return arr
.map(item => `<div>${ item }</div>`)
.join(", ");
}
nav.innerHTML = render(arr.slice().sort());
div.innerHTML = render(arr);
{...state, first : {
...state.first,
second : {
...state.first.second,
[action.someId] : {
...state.first.second[action.someId],
fourth : action.someValue
}
}
}}
{...state, first : {
...state.first,
second : {
...state.first.second,
[action.someId] : {
...state.first.second[action.someId],
fourth : action.someValue
}
}
}}
[
...array.slice(0, action.index),
action.item,
...array.slice(action.index)
]
[
...array.slice(0, action.index),
action.item,
...array.slice(action.index)
]
Операция |
Сложность |
Добавление элемента |
О(n) |
Удаление элемента |
О(n) |
Поиск |
О(1)/О(n) |
Эффективна ли неизменяемость?
Чисто функциональные структуры данных
Префиксное дерево (Trie tree)
Операция |
Сложность |
Поиск |
О(|Key|) |
Добавление элемента |
О(|Key|) |
Удаление элемента |
О(|Key|) |
Изменение |
О(|Key|) |
Hash Array Mapped Trie (HAMT)
Immutability в JS
- ImmutableJS
- Seamless-immutable
- Mori.js
List в ImmutableJS
const originalList = List([ 0 ]);
const newList = originalList.set(1, 1);
const newList2 = originalList.set(0, 'overwritten');
originalList.get(0);
List в ImmutableJS
- До 32 элементов - обычный массив
- Свыше 32 элементов - массив массивов до 32 элементов
- Свыше 32*32 элементов - массив массивов массивов до 32 элементов
- Прямая ссылка на последний массив
Map в ImmutableJS
const originalMap = Map({ a: 1 });
const newMap = originalMap.set("b", 1);
const newMap2 = originalMap.set(a, 'overwritten');
originalMap.get(a, 'overwritten');
Map в ImmutableJS
- До 8 элементов - обычный массив [[ключ, значение], ...]
- Свыше 8 (до 32) элементов - Bitmap хэш таблица
- Свыше 32 элементов - хэш массив из Bitmap хэш таблиц
Перестроение DOM в React Fiber
- Построение/сравнение VDOM
- Применение изменений
Приоритеты React Fiber
- Синхронные операции
- Задачи для следующего такта
- Анимации
- Высокоприоритетные
- Низкоприоритетные
- Задачи на изменения вне экрана
Структуры данных в React Fiber
- Стек
- Очередь с приоритетами
Стек на массиве
Операция |
Сложность |
Добавление элемента |
О(1) |
Удаление элемента |
О(1) |
Очередь на связанном списке
Операция |
Сложность |
Добавление элемента |
О(1) |
Удаление элемента |
О(1) |
Очередь с приоритетами
Операция/Сложность |
Массив |
Сорт. массив |
Связанный список |
Добавление элемента |
О(1) |
О(n) |
О(n) |
Получение элемента |
О(n) |
О(1) |
О(1) |
Кучи
- Двоичная куча
- Биномиальная куча
- Фибоначчиева куча
- Тонкая куча
- Толстая куча
- и другие
Двоичная куча для максимума
- Значение в любой вершине не меньше, чем значения её потомков
- На i-ом слое 2^i вершин, кроме последнего.
- Последний слой заполнен слева направо
Очередь на двоичной куче
Операция |
Сложность |
Добавление элемента |
О(log n) |
Получение элемента |
О(log n) |
Поиск макс. элемента |
О(1) |
Что использует React Fiber?
Очередь с приоритетами
Операция/Сложность |
Куча |
Связанный список |
Добавление элемента |
О(log n) |
О(n) |
Получение элемента |
О(log n) |
О(1) |
Поиск макс. элемента |
О(1) |
О(1) |
Выводы
- Интересуйтесь структурами данных и соответствующими им алгоритмами
- Почаще заглядывайте в код инструментов, которыми вы пользуетесь
- Не бойтесь неизменяемых структур данных
- Использование правильной структуры данных, позволяет решить задачу эффективнее
Вопросы на сегодня:
- Для чего фронтенд программисту нужно знать структуры данных и алгоритмы?