HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p><strong>Проверка наличия объекта - одна из ключевых задач в программировании. Она встречается при разработке практически любого программного продукта. Чтобы ускорить поиск объекта, разработчики применяют фильтр Блума. В этой статье мы расскажем, почему появился фильтр Блума и в каких случаях его применяют. Также познакомим с принципами работы с фильтром и научим пользоваться им.</strong></p>
1 <p><strong>Проверка наличия объекта - одна из ключевых задач в программировании. Она встречается при разработке практически любого программного продукта. Чтобы ускорить поиск объекта, разработчики применяют фильтр Блума. В этой статье мы расскажем, почему появился фильтр Блума и в каких случаях его применяют. Также познакомим с принципами работы с фильтром и научим пользоваться им.</strong></p>
2 <p>Эта тема не входит в стандартную программу подготовки программистов. Если вы изучите ее и примените на практике, то станете более востребованным специалистом.</p>
2 <p>Эта тема не входит в стандартную программу подготовки программистов. Если вы изучите ее и примените на практике, то станете более востребованным специалистом.</p>
3 <h2>Содержание</h2>
3 <h2>Содержание</h2>
4 <ul><li><a>Как ищут объект</a></li>
4 <ul><li><a>Как ищут объект</a></li>
5 <li><a>Что такое фильтр Блума и как он работает</a></li>
5 <li><a>Что такое фильтр Блума и как он работает</a></li>
6 <li><a>Какие у фильтра Блума недостатки и ограничения</a></li>
6 <li><a>Какие у фильтра Блума недостатки и ограничения</a></li>
7 <li><a>Где применяется фильтр Блума</a></li>
7 <li><a>Где применяется фильтр Блума</a></li>
8 <li><a>Как фильтр Блума реализуется на JavaScript</a></li>
8 <li><a>Как фильтр Блума реализуется на JavaScript</a></li>
9 <li><a>Вывод</a></li>
9 <li><a>Вывод</a></li>
10 <li><a>Дополнительные материалы</a></li>
10 <li><a>Дополнительные материалы</a></li>
11 </ul><h2>Как ищут объект</h2>
11 </ul><h2>Как ищут объект</h2>
12 <p>Чтобы найти объект, применяют разные способы. Можно сделать последовательный перебор или использовать хеш-таблицы. При этом каждый из этих способов применяется в определенных случаях, и у них есть ограничения.</p>
12 <p>Чтобы найти объект, применяют разные способы. Можно сделать последовательный перебор или использовать хеш-таблицы. При этом каждый из этих способов применяется в определенных случаях, и у них есть ограничения.</p>
13 <p>Например, поиск в таблице маршрутизации на роутере должен быть максимально быстрым, притом что скорость процессора и доступная память устройства ограничены.</p>
13 <p>Например, поиск в таблице маршрутизации на роутере должен быть максимально быстрым, притом что скорость процессора и доступная память устройства ограничены.</p>
14 <p>Предположим, вы играете с другом в "Города". Вы плохо знаете географию и поэтому не можете утверждать, что Норфолк - это не город.</p>
14 <p>Предположим, вы играете с другом в "Города". Вы плохо знаете географию и поэтому не можете утверждать, что Норфолк - это не город.</p>
15 <p>Программист решил бы эту проблему так: разработал программу, загрузил в нее справочник всех городов планеты и выполнил поиск. Но это не понравится сопернику, так как ему придется долго ждать.</p>
15 <p>Программист решил бы эту проблему так: разработал программу, загрузил в нее справочник всех городов планеты и выполнил поиск. Но это не понравится сопернику, так как ему придется долго ждать.</p>
16 <p>Допустим, поиск города в неотсортированном списке занимает время О(N). Всего в мире насчитывается 2 667 417 городов. Предположим, что наш компьютер может выполнять 1 000 операций в секунду. Тогда время на поиск составит 2667,5 секунды - более 44 минут.</p>
16 <p>Допустим, поиск города в неотсортированном списке занимает время О(N). Всего в мире насчитывается 2 667 417 городов. Предположим, что наш компьютер может выполнять 1 000 операций в секунду. Тогда время на поиск составит 2667,5 секунды - более 44 минут.</p>
17 <p>Это слишком долго для игры в "Города", поэтому нужно ускорить процесс. Например, купить компьютер помощнее, но тогда придется потратиться. Решить вопрос можно менее затратно - улучшить алгоритм, который сократит время поиска.</p>
17 <p>Это слишком долго для игры в "Города", поэтому нужно ускорить процесс. Например, купить компьютер помощнее, но тогда придется потратиться. Решить вопрос можно менее затратно - улучшить алгоритм, который сократит время поиска.</p>
18 <p>Например, можно использовать хеш-таблицы, чья скорость поиска в идеальном случае считается равной О(1). Только она требует больших затрат по памяти и зависит от выбранного разработчиком метода хеширования.</p>
18 <p>Например, можно использовать хеш-таблицы, чья скорость поиска в идеальном случае считается равной О(1). Только она требует больших затрат по памяти и зависит от выбранного разработчиком метода хеширования.</p>
19 <p>Из-за того, что в программировании не было идеального способа решения такой проблемы, придумали вероятностную структуру данных - фильтр Блума. С его помощью не ищут объект, а проверяют, что его не существует. Еще он решает поставленную задачу за время О(1) и не размещает все объекты в оперативной памяти.</p>
19 <p>Из-за того, что в программировании не было идеального способа решения такой проблемы, придумали вероятностную структуру данных - фильтр Блума. С его помощью не ищут объект, а проверяют, что его не существует. Еще он решает поставленную задачу за время О(1) и не размещает все объекты в оперативной памяти.</p>
20 <h2>Что такое фильтр Блума и как он работает</h2>
20 <h2>Что такое фильтр Блума и как он работает</h2>
21 <p>Фильтр Блума - это инструмент разработчика, который ускоряет проверку наличия объекта.</p>
21 <p>Фильтр Блума - это инструмент разработчика, который ускоряет проверку наличия объекта.</p>
22 <p>Фильтр состоит из двух частей: нескольких хеш-функций, которые преобразуют элементы, добавляемые в фильтр, и массива битов. Результатом вычисления хеш-функций будут позиции в массиве, значения которых будут равны единице.</p>
22 <p>Фильтр состоит из двух частей: нескольких хеш-функций, которые преобразуют элементы, добавляемые в фильтр, и массива битов. Результатом вычисления хеш-функций будут позиции в массиве, значения которых будут равны единице.</p>
23 <p>Проверка вхождения проходит аналогично: к искомому элементу применяются те же хеш-функции. При этом номера полученных адресов сравниваются с соответствующими адресами в массиве битов.</p>
23 <p>Проверка вхождения проходит аналогично: к искомому элементу применяются те же хеш-функции. При этом номера полученных адресов сравниваются с соответствующими адресами в массиве битов.</p>
24 <p>Далее события могут развиваться по двум вариантам:</p>
24 <p>Далее события могут развиваться по двум вариантам:</p>
25 <ol><li><p>Хотя бы в одном из адресов содержится ноль - объекта нет в исходной последовательности.</p>
25 <ol><li><p>Хотя бы в одном из адресов содержится ноль - объекта нет в исходной последовательности.</p>
26 </li>
26 </li>
27 <li><p>Во всех адресах содержатся только единицы - искомый объект, возможно, присутствует в исходной последовательности.</p>
27 <li><p>Во всех адресах содержатся только единицы - искомый объект, возможно, присутствует в исходной последовательности.</p>
28 </li>
28 </li>
29 </ol><p>Например, так выглядит фильтр последовательности трех элементов - x, y и z:</p>
29 </ol><p>Например, так выглядит фильтр последовательности трех элементов - x, y и z:</p>
30 <p>Фильтр состоит из трех хеш-функций и битового массива длиной 18. Когда элемент добавляется, к нему применяется по три хеш-функции - они возвращаются в результате позиции в массиве.</p>
30 <p>Фильтр состоит из трех хеш-функций и битового массива длиной 18. Когда элемент добавляется, к нему применяется по три хеш-функции - они возвращаются в результате позиции в массиве.</p>
31 <p>В местах, где указываются функции, устанавливаем значение элемента массива равным единице. Далее проверяется наличие элемента w.</p>
31 <p>В местах, где указываются функции, устанавливаем значение элемента массива равным единице. Далее проверяется наличие элемента w.</p>
32 <p>В нашем примере проверка завершается неудачно, так как хеш-функции вернули позиции массива, в одной из которых содержится ноль.</p>
32 <p>В нашем примере проверка завершается неудачно, так как хеш-функции вернули позиции массива, в одной из которых содержится ноль.</p>
33 <p>Вернемся к игре, где один из соперников назвал город Норфолк. Чтобы узнать, есть ли такой город, применим фильтр Блума.</p>
33 <p>Вернемся к игре, где один из соперников назвал город Норфолк. Чтобы узнать, есть ли такой город, применим фильтр Блума.</p>
34 <p>Составим полный список всех городов мира и применим для каждого элемента хеш-функции. У нас получится следующий массив:</p>
34 <p>Составим полный список всех городов мира и применим для каждого элемента хеш-функции. У нас получится следующий массив:</p>
35 <p>Проверим работу программы для нашего списка на Москве:</p>
35 <p>Проверим работу программы для нашего списка на Москве:</p>
36 <p>Во всех адресах содержатся единицы - город Москва, возможно, есть в списке.</p>
36 <p>Во всех адресах содержатся единицы - город Москва, возможно, есть в списке.</p>
37 <p>Теперь проверим наличие Норфолка в базе:</p>
37 <p>Теперь проверим наличие Норфолка в базе:</p>
38 <p>Одна из ячеек содержит ноль - города Норфолк нет в списке. Чтобы вычислить это, нам понадобились доли секунды, а не 40 минут для перебора каждого элемента списка.</p>
38 <p>Одна из ячеек содержит ноль - города Норфолк нет в списке. Чтобы вычислить это, нам понадобились доли секунды, а не 40 минут для перебора каждого элемента списка.</p>
39 <p>Фильтр Блума ускоряет поиск объекта, что важно для разработки. При этом у него есть побочный эффект - результат бывает неопределенным. Например, когда хеш-функции вернули все позиции массива с единицей. Это означает, что объект, возможно, есть в исходной последовательности. Такой побочный эффект - главный недостаток фильтра Блума.</p>
39 <p>Фильтр Блума ускоряет поиск объекта, что важно для разработки. При этом у него есть побочный эффект - результат бывает неопределенным. Например, когда хеш-функции вернули все позиции массива с единицей. Это означает, что объект, возможно, есть в исходной последовательности. Такой побочный эффект - главный недостаток фильтра Блума.</p>
40 <h2>Какие у фильтра Блума недостатки и ограничения</h2>
40 <h2>Какие у фильтра Блума недостатки и ограничения</h2>
41 <p>У фильтра Блума есть важное преимущество: он экономит память и увеличивает скорость проверки информации о наличии конкретного объекта. Но из-за этого проявляется существенный недостаток.</p>
41 <p>У фильтра Блума есть важное преимущество: он экономит память и увеличивает скорость проверки информации о наличии конкретного объекта. Но из-за этого проявляется существенный недостаток.</p>
42 <p>Фильтр работает с косвенными данными, которые вычисляются на основе хеш-функций. Они подвергаются<strong>коллизиям</strong>- когда при разных входных документах с некоторой частотой выдаются одинаковые ответы.</p>
42 <p>Фильтр работает с косвенными данными, которые вычисляются на основе хеш-функций. Они подвергаются<strong>коллизиям</strong>- когда при разных входных документах с некоторой частотой выдаются одинаковые ответы.</p>
43 <p>Из-за этого недостатка у фильтра Блума появляется ограничение -<strong>вероятность ошибки</strong>. Фильтр отвечает, что объект, возможно, есть, хотя его нет в изначальной последовательности.</p>
43 <p>Из-за этого недостатка у фильтра Блума появляется ограничение -<strong>вероятность ошибки</strong>. Фильтр отвечает, что объект, возможно, есть, хотя его нет в изначальной последовательности.</p>
44 <p>Вероятность ошибки можно уменьшить, если подобрать оптимальное количество хеш-функций, которые обрабатывают входную последовательность. Еще вероятность ошибки можно снизить, если увеличить размерность массива битов.</p>
44 <p>Вероятность ошибки можно уменьшить, если подобрать оптимальное количество хеш-функций, которые обрабатывают входную последовательность. Еще вероятность ошибки можно снизить, если увеличить размерность массива битов.</p>
45 <p>Представим, что мы продолжаем играть в "Города" и решили уменьшить вероятность ложноположительного ответа.</p>
45 <p>Представим, что мы продолжаем играть в "Города" и решили уменьшить вероятность ложноположительного ответа.</p>
46 <p>Если мы подберем оптимальное количество хеш-функций, вероятность ошибки составит 0,001 - 0,1%. Это значение нашли через<a>вероятность ложноположительного срабатывания</a>.</p>
46 <p>Если мы подберем оптимальное количество хеш-функций, вероятность ошибки составит 0,001 - 0,1%. Это значение нашли через<a>вероятность ложноположительного срабатывания</a>.</p>
47 <p>Получается, что на каждую тысячу названных игроками городов только один будет определен некорректно - возможно существующий. Это можно признать допустимым для игры.</p>
47 <p>Получается, что на каждую тысячу названных игроками городов только один будет определен некорректно - возможно существующий. Это можно признать допустимым для игры.</p>
48 <p>Фильтр Блума все равно выдаст неопределенный ответ, если уменьшить вероятность ошибки.</p>
48 <p>Фильтр Блума все равно выдаст неопределенный ответ, если уменьшить вероятность ошибки.</p>
49 <p>Если нам нужен точный ответ, то можно выполнить традиционный поиск в исходной последовательности. Поэтому классические методы выбора оптимального алгоритма поиска все равно применяются.</p>
49 <p>Если нам нужен точный ответ, то можно выполнить традиционный поиск в исходной последовательности. Поэтому классические методы выбора оптимального алгоритма поиска все равно применяются.</p>
50 <p>Фильтр Блума сэкономит время на обращение к диску и уменьшит их частоту. Но это можно применить только в качестве предварительного фильтра запросов к основной последовательности.</p>
50 <p>Фильтр Блума сэкономит время на обращение к диску и уменьшит их частоту. Но это можно применить только в качестве предварительного фильтра запросов к основной последовательности.</p>
51 <p>В таком виде структура данных используется в поисковых движках типа Google. С ее помощью можно не обращаться к ресурсам, на которых гарантированно отсутствует информация из поискового запроса.</p>
51 <p>В таком виде структура данных используется в поисковых движках типа Google. С ее помощью можно не обращаться к ресурсам, на которых гарантированно отсутствует информация из поискового запроса.</p>
52 <p>Несмотря на то, что фильтр Блума придумали более 50 лет назад, он до сих пор активно применяется разработчиками. Рассмотрим, где с ним можно столкнуться.</p>
52 <p>Несмотря на то, что фильтр Блума придумали более 50 лет назад, он до сих пор активно применяется разработчиками. Рассмотрим, где с ним можно столкнуться.</p>
53 <h2>Где применяется фильтр Блума</h2>
53 <h2>Где применяется фильтр Блума</h2>
54 <p>По сравнению со старыми компьютерами, вычислительная мощность современных устройств выросла. При этом увеличилась и сложность задач. Некоторые из них могут решаться несколько дней из-за больших данных. В итоге запросы долго обрабатываются, памяти не хватает, а оборудование быстро изнашивается.</p>
54 <p>По сравнению со старыми компьютерами, вычислительная мощность современных устройств выросла. При этом увеличилась и сложность задач. Некоторые из них могут решаться несколько дней из-за больших данных. В итоге запросы долго обрабатываются, памяти не хватает, а оборудование быстро изнашивается.</p>
55 <p>В этом случае помогает фильтр Блума, который применяется в следующих случаях:</p>
55 <p>В этом случае помогает фильтр Блума, который применяется в следующих случаях:</p>
56 <ol><li><p><strong>Поиск в интернете</strong>. Здесь фильтр позволяет поисковой машине не сканировать ресурсы, на которых точно нет информации из поискового запроса. Это экономит время пользователя.</p>
56 <ol><li><p><strong>Поиск в интернете</strong>. Здесь фильтр позволяет поисковой машине не сканировать ресурсы, на которых точно нет информации из поискового запроса. Это экономит время пользователя.</p>
57 </li>
57 </li>
58 <li><p><strong>Таблицы маршрутизации</strong>. Например, черные списки IP-адресов, куда нельзя перенаправлять запросы. Эту информацию нужно получать максимально быстро. Ниже на рисунке пример проверки двух IP-адресов в черном списке:</p>
58 <li><p><strong>Таблицы маршрутизации</strong>. Например, черные списки IP-адресов, куда нельзя перенаправлять запросы. Эту информацию нужно получать максимально быстро. Ниже на рисунке пример проверки двух IP-адресов в черном списке:</p>
59 </li>
59 </li>
60 </ol><p>Адреса 112.64.90.12 точно нет в списке, так как одна из функций вернула позицию с нулевым значением. Для адреса 178.23.12.63 нужно уточнение, так как фильтр отвечает, что адрес, возможно, есть в черном списке. Если бы маршрутизатор проверял каждый из адресов полностью, скорость работы интернета была бы значительно ниже</p>
60 </ol><p>Адреса 112.64.90.12 точно нет в списке, так как одна из функций вернула позицию с нулевым значением. Для адреса 178.23.12.63 нужно уточнение, так как фильтр отвечает, что адрес, возможно, есть в черном списке. Если бы маршрутизатор проверял каждый из адресов полностью, скорость работы интернета была бы значительно ниже</p>
61 <ol><li><p><strong>Системы проверки орфографии</strong>. В этом случае компьютер может выделить слово, которого нет в словаре. Так не придется нагружать устройство после каждого нажатия клавиши.</p>
61 <ol><li><p><strong>Системы проверки орфографии</strong>. В этом случае компьютер может выделить слово, которого нет в словаре. Так не придется нагружать устройство после каждого нажатия клавиши.</p>
62 </li>
62 </li>
63 <li><p><strong>Криптокошельки</strong>. Фильтр Блума используется, чтобы искать транзакции. В результате с некоторой вероятностью можно утверждать, что транзакция в наличии, или ее нет.</p>
63 <li><p><strong>Криптокошельки</strong>. Фильтр Блума используется, чтобы искать транзакции. В результате с некоторой вероятностью можно утверждать, что транзакция в наличии, или ее нет.</p>
64 </li>
64 </li>
65 <li><p><strong>В биоинформатике</strong>. Фильтр используется, чтобы искать фрагменты в последовательностях ДНК. Ниже на рисунке видно, как в фильтр Блума добавили цепочку ДНК ACCTAG и искали фрагмент CGTAT:</p>
65 <li><p><strong>В биоинформатике</strong>. Фильтр используется, чтобы искать фрагменты в последовательностях ДНК. Ниже на рисунке видно, как в фильтр Блума добавили цепочку ДНК ACCTAG и искали фрагмент CGTAT:</p>
66 </li>
66 </li>
67 </ol><p><em>Поиск завершается неудачей, так как различается последняя буква в искомой последовательности аминокислот и исходной последовательности ДНК</em></p>
67 </ol><p><em>Поиск завершается неудачей, так как различается последняя буква в искомой последовательности аминокислот и исходной последовательности ДНК</em></p>
68 <p>Список случаев, где применяется фильтр Блума, постоянно пополняется. В сети можно найти публикации об открытии новых мест применения этой структуры данных.</p>
68 <p>Список случаев, где применяется фильтр Блума, постоянно пополняется. В сети можно найти публикации об открытии новых мест применения этой структуры данных.</p>
69 <p>Теперь посмотрим, как фильтр Блума применяется на практике. Поработаем с JavaScript.</p>
69 <p>Теперь посмотрим, как фильтр Блума применяется на практике. Поработаем с JavaScript.</p>
70 <h2>Как фильтр Блума реализуется на JavaScript</h2>
70 <h2>Как фильтр Блума реализуется на JavaScript</h2>
71 <p>Работу с фильтром Блума будем рассматривать по шагам.</p>
71 <p>Работу с фильтром Блума будем рассматривать по шагам.</p>
72 <ol><li>Для начала создадим новый класс, который будет представлять нашу структуру данных. Также создадим к нему конструктор, который в качестве исходных параметров будет принимать размерность массива и количество используемых хеш-функций.</li>
72 <ol><li>Для начала создадим новый класс, который будет представлять нашу структуру данных. Также создадим к нему конструктор, который в качестве исходных параметров будет принимать размерность массива и количество используемых хеш-функций.</li>
73 </ol><p>В свойствах конструктора сохраним входные значения и создадим массив, который проинициализируем нулевыми значениями:</p>
73 </ol><p>В свойствах конструктора сохраним входные значения и создадим массив, который проинициализируем нулевыми значениями:</p>
74 <ol><li>Далее реализуем операцию, которая добавляет элемент исходной последовательности в фильтр. Для этого захешируем исходный объект N раз с помощью различных хеш-функций и по каждому полученному адресу установим значение бита равным единице.</li>
74 <ol><li>Далее реализуем операцию, которая добавляет элемент исходной последовательности в фильтр. Для этого захешируем исходный объект N раз с помощью различных хеш-функций и по каждому полученному адресу установим значение бита равным единице.</li>
75 </ol><p>Чтобы упростить реализацию, мы используем одну хеш-функцию. Она будет незначительно изменять алгоритм хеширования в зависимости от номера функции, с которым ее вызвали.</p>
75 </ol><p>Чтобы упростить реализацию, мы используем одну хеш-функцию. Она будет незначительно изменять алгоритм хеширования в зависимости от номера функции, с которым ее вызвали.</p>
76 <p>Так как в JavaScript нет встроенного метода хеширования строки, будем использовать<a>метод String.hashCode()</a>.</p>
76 <p>Так как в JavaScript нет встроенного метода хеширования строки, будем использовать<a>метод String.hashCode()</a>.</p>
77 <p>Этот алгоритм переводит строку в число, которое суммируется из кодов символов в таблице кодировки. Так как фильтру Блума нужно несколько разных хеш-функций, мы модифицируем исходную строку. Для этого добавим в качестве префикса номера используемой хеш-функции:</p>
77 <p>Этот алгоритм переводит строку в число, которое суммируется из кодов символов в таблице кодировки. Так как фильтру Блума нужно несколько разных хеш-функций, мы модифицируем исходную строку. Для этого добавим в качестве префикса номера используемой хеш-функции:</p>
78 <ol><li>В конце проверим наличие элемента в последовательности. Для этого прогоним хеш-функции для искомого элемента и проверим по каждому адресу значение бита. Если хоть одно значение равно нулю, то элемента точно нет в последовательности:</li>
78 <ol><li>В конце проверим наличие элемента в последовательности. Для этого прогоним хеш-функции для искомого элемента и проверим по каждому адресу значение бита. Если хоть одно значение равно нулю, то элемента точно нет в последовательности:</li>
79 </ol><p>Если бы каждое значение равнялось единице, то элемент, возможно, был в последовательности.</p>
79 </ol><p>Если бы каждое значение равнялось единице, то элемент, возможно, был в последовательности.</p>
80 <h2>Вывод</h2>
80 <h2>Вывод</h2>
81 <p>Вероятностная структура данных фильтр Блума увеличивает скорость проверки информации и показывает, есть ли объект в последовательности.</p>
81 <p>Вероятностная структура данных фильтр Блума увеличивает скорость проверки информации и показывает, есть ли объект в последовательности.</p>
82 <p>Этот инструмент важен для разработчиков, так как не разбирается в стандартных программах обучения, но ценится среди специалистов.</p>
82 <p>Этот инструмент важен для разработчиков, так как не разбирается в стандартных программах обучения, но ценится среди специалистов.</p>
83 <p>Сегодня фильтр используют в поисковых движках, таблицах маршрутизации, системах проверки орфографии и крипто-кошельках. Уже сейчас этот список может быть шире, так как разработчики постоянно ищут новые способы, чтобы применить инструмент.</p>
83 <p>Сегодня фильтр используют в поисковых движках, таблицах маршрутизации, системах проверки орфографии и крипто-кошельках. Уже сейчас этот список может быть шире, так как разработчики постоянно ищут новые способы, чтобы применить инструмент.</p>
84 <p>Если хотите рассмотреть полную версию программной реализации, можете найти ее в<a>Github</a>. Так вы научитесь пользоваться фильтром Блума в полной мере и станете более востребованным специалистом.</p>
84 <p>Если хотите рассмотреть полную версию программной реализации, можете найти ее в<a>Github</a>. Так вы научитесь пользоваться фильтром Блума в полной мере и станете более востребованным специалистом.</p>
85 <h2>Дополнительные материалы</h2>
85 <h2>Дополнительные материалы</h2>
86 <ul><li><a>Пример реализации, разобранный в статье</a></li>
86 <ul><li><a>Пример реализации, разобранный в статье</a></li>
87 <li><a>Основная статья с изложением идей Бертона Блума</a></li>
87 <li><a>Основная статья с изложением идей Бертона Блума</a></li>
88 <li><a>Детали определения вероятности ложноположительного срабатывания</a></li>
88 <li><a>Детали определения вероятности ложноположительного срабатывания</a></li>
89 <li><a>Имплементация алгоритма хеширования строк для JS</a></li>
89 <li><a>Имплементация алгоритма хеширования строк для JS</a></li>
90 </ul><blockquote><h3>Никогда не останавливайтесь:</h3>
90 </ul><blockquote><h3>Никогда не останавливайтесь:</h3>
91 <p>В программировании говорят, что нужно постоянно учиться даже для того, чтобы просто находиться на месте. Развивайтесь с нами - на Хекслете есть<a>сотни курсов по разработке на разных языках и технологиях</a></p>
91 <p>В программировании говорят, что нужно постоянно учиться даже для того, чтобы просто находиться на месте. Развивайтесь с нами - на Хекслете есть<a>сотни курсов по разработке на разных языках и технологиях</a></p>
92 </blockquote>
92 </blockquote>