[{"data":1,"prerenderedAt":1848},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fpython\u002Fst20":386,"\u002Fblog\u002Fpython\u002Fst20-surround":1843},[4],{"title":5,"path":6,"stem":7,"children":8,"page":114},"Blog","\u002Fblog","blog",[9,115,184,329],{"title":10,"path":11,"stem":12,"children":13,"page":114},"Ege","\u002Fblog\u002Fege","blog\u002Fege",[14,18,22,26,30,34,38,42,46,50,54,58,62,66,70,74,78,82,86,90,94,98,102,106,110],{"title":15,"path":16,"stem":17},"ЕГЭ Задание 1","\u002Fblog\u002Fege\u002Ftask1","blog\u002Fege\u002Ftask1",{"title":19,"path":20,"stem":21},"ЕГЭ Задание 10","\u002Fblog\u002Fege\u002Ftask10","blog\u002Fege\u002Ftask10",{"title":23,"path":24,"stem":25},"ЕГЭ Задание 11","\u002Fblog\u002Fege\u002Ftask11","blog\u002Fege\u002Ftask11",{"title":27,"path":28,"stem":29},"ЕГЭ Задание 12","\u002Fblog\u002Fege\u002Ftask12","blog\u002Fege\u002Ftask12",{"title":31,"path":32,"stem":33},"ЕГЭ Задание 13","\u002Fblog\u002Fege\u002Ftask13","blog\u002Fege\u002Ftask13",{"title":35,"path":36,"stem":37},"ЕГЭ Задание 14","\u002Fblog\u002Fege\u002Ftask14","blog\u002Fege\u002Ftask14",{"title":39,"path":40,"stem":41},"ЕГЭ Задание 15","\u002Fblog\u002Fege\u002Ftask15","blog\u002Fege\u002Ftask15",{"title":43,"path":44,"stem":45},"ЕГЭ Задание 16","\u002Fblog\u002Fege\u002Ftask16","blog\u002Fege\u002Ftask16",{"title":47,"path":48,"stem":49},"ЕГЭ Задание 17","\u002Fblog\u002Fege\u002Ftask17","blog\u002Fege\u002Ftask17",{"title":51,"path":52,"stem":53},"ЕГЭ Задание 18","\u002Fblog\u002Fege\u002Ftask18","blog\u002Fege\u002Ftask18",{"title":55,"path":56,"stem":57},"ЕГЭ Задание 19, 20, 21","\u002Fblog\u002Fege\u002Ftask19_20_21","blog\u002Fege\u002Ftask19_20_21",{"title":59,"path":60,"stem":61},"ЕГЭ Задание 2","\u002Fblog\u002Fege\u002Ftask2","blog\u002Fege\u002Ftask2",{"title":63,"path":64,"stem":65},"ЕГЭ Задание 22","\u002Fblog\u002Fege\u002Ftask22","blog\u002Fege\u002Ftask22",{"title":67,"path":68,"stem":69},"ЕГЭ Задание 23","\u002Fblog\u002Fege\u002Ftask23","blog\u002Fege\u002Ftask23",{"title":71,"path":72,"stem":73},"ЕГЭ Задание 24","\u002Fblog\u002Fege\u002Ftask24","blog\u002Fege\u002Ftask24",{"title":75,"path":76,"stem":77},"ЕГЭ Задание 25","\u002Fblog\u002Fege\u002Ftask25","blog\u002Fege\u002Ftask25",{"title":79,"path":80,"stem":81},"ЕГЭ Задание 26","\u002Fblog\u002Fege\u002Ftask26","blog\u002Fege\u002Ftask26",{"title":83,"path":84,"stem":85},"ЕГЭ Задание 27","\u002Fblog\u002Fege\u002Ftask27","blog\u002Fege\u002Ftask27",{"title":87,"path":88,"stem":89},"ЕГЭ Задание 3","\u002Fblog\u002Fege\u002Ftask3","blog\u002Fege\u002Ftask3",{"title":91,"path":92,"stem":93},"ЕГЭ Задание 4","\u002Fblog\u002Fege\u002Ftask4","blog\u002Fege\u002Ftask4",{"title":95,"path":96,"stem":97},"ЕГЭ Задание 5","\u002Fblog\u002Fege\u002Ftask5","blog\u002Fege\u002Ftask5",{"title":99,"path":100,"stem":101},"ЕГЭ Задание 6","\u002Fblog\u002Fege\u002Ftask6","blog\u002Fege\u002Ftask6",{"title":103,"path":104,"stem":105},"ЕГЭ Задание 7","\u002Fblog\u002Fege\u002Ftask7","blog\u002Fege\u002Ftask7",{"title":107,"path":108,"stem":109},"ЕГЭ Задание 8","\u002Fblog\u002Fege\u002Ftask8","blog\u002Fege\u002Ftask8",{"title":111,"path":112,"stem":113},"ЕГЭ Задание 9","\u002Fblog\u002Fege\u002Ftask9","blog\u002Fege\u002Ftask9",false,{"title":116,"path":117,"stem":118,"children":119,"page":114},"Oge","\u002Fblog\u002Foge","blog\u002Foge",[120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180],{"title":121,"path":122,"stem":123},"ОГЭ Задание 1","\u002Fblog\u002Foge\u002Ftask1","blog\u002Foge\u002Ftask1",{"title":125,"path":126,"stem":127},"ОГЭ Задание 10","\u002Fblog\u002Foge\u002Ftask10","blog\u002Foge\u002Ftask10",{"title":129,"path":130,"stem":131},"ОГЭ Задание 11","\u002Fblog\u002Foge\u002Ftask11","blog\u002Foge\u002Ftask11",{"title":133,"path":134,"stem":135},"ОГЭ Задание 12","\u002Fblog\u002Foge\u002Ftask12","blog\u002Foge\u002Ftask12",{"title":137,"path":138,"stem":139},"ОГЭ Задание 13","\u002Fblog\u002Foge\u002Ftask13","blog\u002Foge\u002Ftask13",{"title":141,"path":142,"stem":143},"ОГЭ Задание 14","\u002Fblog\u002Foge\u002Ftask14","blog\u002Foge\u002Ftask14",{"title":145,"path":146,"stem":147},"ОГЭ Задание 15","\u002Fblog\u002Foge\u002Ftask15","blog\u002Foge\u002Ftask15",{"title":149,"path":150,"stem":151},"ОГЭ Задание 16","\u002Fblog\u002Foge\u002Ftask16","blog\u002Foge\u002Ftask16",{"title":153,"path":154,"stem":155},"ОГЭ Задание 2","\u002Fblog\u002Foge\u002Ftask2","blog\u002Foge\u002Ftask2",{"title":157,"path":158,"stem":159},"ОГЭ Задание 3","\u002Fblog\u002Foge\u002Ftask3","blog\u002Foge\u002Ftask3",{"title":161,"path":162,"stem":163},"ОГЭ Задание 4","\u002Fblog\u002Foge\u002Ftask4","blog\u002Foge\u002Ftask4",{"title":165,"path":166,"stem":167},"ОГЭ Задание 5","\u002Fblog\u002Foge\u002Ftask5","blog\u002Foge\u002Ftask5",{"title":169,"path":170,"stem":171},"ОГЭ Задание 6","\u002Fblog\u002Foge\u002Ftask6","blog\u002Foge\u002Ftask6",{"title":173,"path":174,"stem":175},"ОГЭ Задание 7","\u002Fblog\u002Foge\u002Ftask7","blog\u002Foge\u002Ftask7",{"title":177,"path":178,"stem":179},"ОГЭ Задание 8","\u002Fblog\u002Foge\u002Ftask8","blog\u002Foge\u002Ftask8",{"title":181,"path":182,"stem":183},"ОГЭ Задание 9","\u002Fblog\u002Foge\u002Ftask9","blog\u002Foge\u002Ftask9",{"title":185,"path":186,"stem":187,"children":188,"page":114},"Python","\u002Fblog\u002Fpython","blog\u002Fpython",[189,193,197,201,205,209,213,217,221,225,229,233,237,241,245,249,253,257,261,265,269,273,277,281,285,289,293,297,301,305,309,313,317,321,325],{"title":190,"path":191,"stem":192},"Знакомство с синтаксисом","\u002Fblog\u002Fpython\u002Fst1","blog\u002Fpython\u002Fst1",{"title":194,"path":195,"stem":196},"Отладка","\u002Fblog\u002Fpython\u002Fst10","blog\u002Fpython\u002Fst10",{"title":198,"path":199,"stem":200},"Модули и пакеты","\u002Fblog\u002Fpython\u002Fst11","blog\u002Fpython\u002Fst11",{"title":202,"path":203,"stem":204},"Кортежи","\u002Fblog\u002Fpython\u002Fst12","blog\u002Fpython\u002Fst12",{"title":206,"path":207,"stem":208},"Знакомство со списками","\u002Fblog\u002Fpython\u002Fst13","blog\u002Fpython\u002Fst13",{"title":210,"path":211,"stem":212},"Списки и циклы","\u002Fblog\u002Fpython\u002Fst14","blog\u002Fpython\u002Fst14",{"title":214,"path":215,"stem":216},"Использование списков ч.1","\u002Fblog\u002Fpython\u002Fst15","blog\u002Fpython\u002Fst15",{"title":218,"path":219,"stem":220},"Использование списков ч.2","\u002Fblog\u002Fpython\u002Fst16","blog\u002Fpython\u002Fst16",{"title":222,"path":223,"stem":224},"Использование списков ч.3","\u002Fblog\u002Fpython\u002Fst17","blog\u002Fpython\u002Fst17",{"title":226,"path":227,"stem":228},"Словари","\u002Fblog\u002Fpython\u002Fst18","blog\u002Fpython\u002Fst18",{"title":230,"path":231,"stem":232},"Множества","\u002Fblog\u002Fpython\u002Fst19","blog\u002Fpython\u002Fst19",{"title":234,"path":235,"stem":236},"Переменные","\u002Fblog\u002Fpython\u002Fst2","blog\u002Fpython\u002Fst2",{"title":238,"path":239,"stem":240},"Хеш-таблицы","\u002Fblog\u002Fpython\u002Fst20","blog\u002Fpython\u002Fst20",{"title":242,"path":243,"stem":244},"Решето Эратосфена","\u002Fblog\u002Fpython\u002Fst21","blog\u002Fpython\u002Fst21",{"title":246,"path":247,"stem":248},"Длинная арифметика","\u002Fblog\u002Fpython\u002Fst22","blog\u002Fpython\u002Fst22",{"title":250,"path":251,"stem":252},"Декораторы функций","\u002Fblog\u002Fpython\u002Fst23","blog\u002Fpython\u002Fst23",{"title":254,"path":255,"stem":256},"Знакомство с алгоритмами","\u002Fblog\u002Fpython\u002Fst24","blog\u002Fpython\u002Fst24",{"title":258,"path":259,"stem":260},"Бинарный поиск – примеры задач","\u002Fblog\u002Fpython\u002Fst25","blog\u002Fpython\u002Fst25",{"title":262,"path":263,"stem":264},"Сортировка выбором","\u002Fblog\u002Fpython\u002Fst26","blog\u002Fpython\u002Fst26",{"title":266,"path":267,"stem":268},"Рекурсия и стек","\u002Fblog\u002Fpython\u002Fst27","blog\u002Fpython\u002Fst27",{"title":270,"path":271,"stem":272},"Быстрая сортировка","\u002Fblog\u002Fpython\u002Fst28","blog\u002Fpython\u002Fst28",{"title":274,"path":275,"stem":276},"Поиск в ширину","\u002Fblog\u002Fpython\u002Fst29","blog\u002Fpython\u002Fst29",{"title":278,"path":279,"stem":280},"Работа со строками","\u002Fblog\u002Fpython\u002Fst3","blog\u002Fpython\u002Fst3",{"title":282,"path":283,"stem":284},"Поиск в глубину","\u002Fblog\u002Fpython\u002Fst30","blog\u002Fpython\u002Fst30",{"title":286,"path":287,"stem":288},"Сбалансированные деревья","\u002Fblog\u002Fpython\u002Fst31","blog\u002Fpython\u002Fst31",{"title":290,"path":291,"stem":292},"Алгоритм Дейкстры","\u002Fblog\u002Fpython\u002Fst32","blog\u002Fpython\u002Fst32",{"title":294,"path":295,"stem":296},"Жадные алгоритмы","\u002Fblog\u002Fpython\u002Fst33","blog\u002Fpython\u002Fst33",{"title":298,"path":299,"stem":300},"Динамическое программирование","\u002Fblog\u002Fpython\u002Fst34","blog\u002Fpython\u002Fst34",{"title":302,"path":303,"stem":304},"Алгоритм k ближайших соседей","\u002Fblog\u002Fpython\u002Fst35","blog\u002Fpython\u002Fst35",{"title":306,"path":307,"stem":308},"Типы данных","\u002Fblog\u002Fpython\u002Fst4","blog\u002Fpython\u002Fst4",{"title":310,"path":311,"stem":312},"О функциях","\u002Fblog\u002Fpython\u002Fst5","blog\u002Fpython\u002Fst5",{"title":314,"path":315,"stem":316},"Свойства и методы","\u002Fblog\u002Fpython\u002Fst6","blog\u002Fpython\u002Fst6",{"title":318,"path":319,"stem":320},"Определение функций","\u002Fblog\u002Fpython\u002Fst7","blog\u002Fpython\u002Fst7",{"title":322,"path":323,"stem":324},"Логика","\u002Fblog\u002Fpython\u002Fst8","blog\u002Fpython\u002Fst8",{"title":326,"path":327,"stem":328},"Циклы","\u002Fblog\u002Fpython\u002Fst9","blog\u002Fpython\u002Fst9",{"title":330,"path":331,"stem":332,"children":333,"page":114},"Toi","\u002Fblog\u002Ftoi","blog\u002Ftoi",[334,338,342,346,350,354,358,362,366,370,374,378,382],{"title":335,"path":336,"stem":337},"Информация и информационные процессы","\u002Fblog\u002Ftoi\u002Fst1","blog\u002Ftoi\u002Fst1",{"title":339,"path":340,"stem":341},"Электронные таблицы","\u002Fblog\u002Ftoi\u002Fst10","blog\u002Ftoi\u002Fst10",{"title":343,"path":344,"stem":345},"Система, её свойства и компоненты. Моделирование","\u002Fblog\u002Ftoi\u002Fst11","blog\u002Ftoi\u002Fst11",{"title":347,"path":348,"stem":349},"Представление информации в компьютере","\u002Fblog\u002Ftoi\u002Fst12","blog\u002Ftoi\u002Fst12",{"title":351,"path":352,"stem":353},"Средства информационно-коммуникационных технологий. Файловая система","\u002Fblog\u002Ftoi\u002Fst13","blog\u002Ftoi\u002Fst13",{"title":355,"path":356,"stem":357},"Комбинаторика","\u002Fblog\u002Ftoi\u002Fst2","blog\u002Ftoi\u002Fst2",{"title":359,"path":360,"stem":361},"Адресация в интернете","\u002Fblog\u002Ftoi\u002Fst3","blog\u002Ftoi\u002Fst3",{"title":363,"path":364,"stem":365},"Измерение количества информации","\u002Fblog\u002Ftoi\u002Fst4","blog\u002Ftoi\u002Fst4",{"title":367,"path":368,"stem":369},"Системы счисления","\u002Fblog\u002Ftoi\u002Fst5","blog\u002Ftoi\u002Fst5",{"title":371,"path":372,"stem":373},"Диаграммы Эйлера — Венна","\u002Fblog\u002Ftoi\u002Fst6","blog\u002Ftoi\u002Fst6",{"title":375,"path":376,"stem":377},"Условие Фано","\u002Fblog\u002Ftoi\u002Fst7","blog\u002Ftoi\u002Fst7",{"title":379,"path":380,"stem":381},"Теория графов","\u002Fblog\u002Ftoi\u002Fst8","blog\u002Ftoi\u002Fst8",{"title":383,"path":384,"stem":385},"Алгебра логики","\u002Fblog\u002Ftoi\u002Fst9","blog\u002Ftoi\u002Fst9",{"id":387,"title":238,"author":388,"body":393,"date":1834,"description":1835,"extension":1836,"image":1837,"meta":1838,"minRead":1839,"navigation":764,"num":1840,"path":239,"seo":1841,"stem":240,"__hash__":1842},"python\u002Fblog\u002Fpython\u002Fst20.md",{"name":389,"avatar":390},"Штана Альберт Игоревич",{"src":391,"alt":392},"me.jpg","@ashtana",{"type":394,"value":395,"toc":1815},"minimark",[396,400,405,414,479,482,487,490,500,503,514,526,532,535,542,556,564,594,600,668,671,691,694,702,706,709,717,734,737,824,827,830,881,888,893,896,925,928,934,949,954,972,977,999,1004,1028,1033,1059,1062,1102,1105,1110,1128,1133,1157,1162,1178,1181,1185,1188,1192,1195,1203,1206,1214,1217,1231,1234,1282,1285,1304,1307,1310,1317,1321,1324,1338,1341,1362,1369,1372,1456,1459,1498,1501,1504,1508,1511,1522,1529,1537,1540,1616,1619,1624,1628,1631,1639,1642,1649,1698,1705,1708,1716,1719,1723,1730,1738,1742,1745,1748,1751,1755,1765,1768,1771,1785,1791,1793,1797,1808,1811],[397,398,238],"h2",{"id":399},"хеш-таблицы",[401,402],"card-collapsible",{":isList":403,"title":404},"[\"Вы узнаете о хэш-таблицах как одной из базовых структур данных. Хеш-таблицы находят множество применений; В этой статье рассматриваются распространённые варианты использования.\",\"Вы изучите устройство хеш-таблиц: реализацию, хеш-функции и коллизии. Это поможет понять, как анализируется производительность хеш-таблицы.\"]","Из этой статьи вы узнаете",[406,407,408,409,413],"p",{},"Представьте, что вы продавец в магазине. Когда клиент покупает товары, вы проверяете их цены по прайс-листу(по книге или таблице).\nЕсли записи не упорядочены по алфавиту и их очень много, то поиск, например, какого‑нибудь слова «персики» в каждой строке займёт слишком много времени.\nФактически, может получиться линейный поиск, где необходимо проверять каждую запись.\nЭто займёт времени: O(n).\nЕсли прайс-лист упорядочен по алфавиту, вы сможете воспользоваться бинарным поиском(",[410,411,412],"a",{"href":255},"что такое бинарный поиск?","),\nвремя выполнения которого составляет всего O(log n).\nПредположим вы можете посмотреть 10 записей за секунду. Вы знаете, что двоичный поиск работает очень быстро. Но сам процесс поиска — это каждый раз рутинная работа даже для отсортированного списка.\nПока осуществляется поиск — клиент ждёт. Гораздо удобнее было бы завести \"помощника\", который помнит все названия товаров и их цены.\nТогда ничего искать вообще не придётся: вы спрашиваете \"помощника\", а он мгновенно отвечает.\nПолучается что \"помощник\" может сообщать за время O(1) (почти мгновенно) цену любого товара. Соответственно он сработает ещё быстрее чем бинарный(двоичный) поиск.",[415,416,417,436],"table",{},[418,419,420],"thead",{},[421,422,423,427,430,433],"tr",{},[424,425,426],"th",{},"Кол-во элементов",[424,428,429],{},"Простой поиск O(n)",[424,431,432],{},"Бинарный поиск O(log n)",[424,434,435],{},"\"Помощник\" O(1)",[437,438,439,454,466],"tbody",{},[421,440,441,445,448,451],{},[442,443,444],"td",{},"100",[442,446,447],{},"10 сек",[442,449,450],{},"1 сек",[442,452,453],{},"0.001 сек",[421,455,456,459,462,464],{},[442,457,458],{},"1000",[442,460,461],{},"1.6 мин",[442,463,450],{},[442,465,453],{},[421,467,468,471,474,477],{},[442,469,470],{},"10000",[442,472,473],{},"16.6 мин",[442,475,476],{},"2 сек",[442,478,453],{},[406,480,481],{},"Где взять такого помощника?\nОбратимся к структурам данных. Пока возможно вам известны две структуры данных: массивы и списки(о стеках речь не пойдёт, потому что в них нормальный поиск не возможен).\nПрайс-лист в магазине или книгу можно организовать в виде массива.\nНо каждый элемент такого прайс-листа или книги в массиве на самом деле состоит должен будет состоять из двух элементов: названия товара и цены.\nЕсли отсортировать массив по имени, вы сможете проводить по нему бинарный поиск для определения цены товара по его имени.\nЭто значит, что поиск будет выполняться за время O(log n). Но нам ведь нужен поиск или \"помощник\" который бы выдавал нам цену по имени практически мгновенно!\nВ этом нам помогут хеш-функция.",[483,484,486],"h3",{"id":485},"хеш-функция","Хеш-функция",[406,488,489],{},"Хеш-функция представляет собой функцию, которая получает на вход строку и возвращает число.\nПо-научному говорят, что хеш-функция \"отображает строки на числа\".\nОднако, хеш-функция должна соответствовать некоторым требованиям.",[491,492,493,497],"ul",{},[494,495,496],"li",{},"Она должна быть последовательной. Допустим, вы передали ей строку \"яблоки\" и получили 5.\nЭто значит, что каждый раз в будущем передавая ей строку \"яблоки\", вы получите число 5. Без этого она бесполезна.",[494,498,499],{},"Разным словам должны соответствовать разные числа.\nНапример, хеш-функция, которая возвращает 1 для каждого полученного ею слова, никуда не годится.\nВ идеале каждое входное слово должно отображаться на своё число.",[406,501,502],{},"Зачем это нужно, чтобы хеш-функция связывала строки и числа? Это нужно, чтобы реализовать нашего \"помощника\".\nНачнём с пустого массива. Все цены будут храниться в этом массиве, передадим хеш-функции строку \"яблоки\".\nХеш-функция пусть вернёт нам значение \"5\". Сохраним цену яблок в элементе массива под индексом 5.\nДобавим хлеб. Передадим хеш-функции строку \"хлеб\". Получим число 3. Сохраним цену на хлеб в массиве под индексом 3 и т.д.\nПродолжать можно действовать так, и со временем весь массив будет заполнен ценами на товары.\nА теперь запрашиваете: сколько стоит \"хлеб\"?\nИскать в массиве при этом ничего не нужно. Нужно просто передать строку \"хлеб\" хеш-функции.\nРезультат скажет, что значение цены находится под индексом 3, мы цену оттуда и возьмём.\nПолучается, что хеш-функция всегда сообщает нам, где цена хранится. Такое решение работает потому что:",[491,504,505,508,511],{},[494,506,507],{},"Хеш функция неизменно связывает название с одним числом(индексом). Каждый раз, когда она вызывается для строки \"хлеб\",\nвы получаете от неё одно и то же число. При первом вызове этой функции вы узнаете, где следует сохранить цену товара,\nа при последующих вызовах она сообщает, где взять эту цену.",[494,509,510],{},"Хеш-функция связывает разные строки с разными числами. Для каждой строки получается своя позиция массива, в которой сохраняется цена товара.",[494,512,513],{},"Хеш-функция знает размер массива и должна возвращать только действительные индексы.\nТаким образом, если размер массива равен 20 элементам, хеш-функция не вернёт 100, потому что это значение не является действительным индексом.",[406,515,516,517,521,522,525],{},"Таким образом мы создали \"помощника\" по магазину который всегда знает цену по названию!\nСвязав воедино хеш-функцию и массив, мы получили структуру данных, которая называется ",[518,519,520],"em",{},"хеш-таблица",".\nХеш-таблица это первая структура данных, с которой связана дополнительная логика.\nМассивы и списки напрямую отображаются на адреса памяти, но хеш-таблицы устроены более умно.\nОни определяют место хранения элементов с помощью ",[518,523,524],{},"хеш-функций",".",[527,528,529],"blockquote",{},[406,530,531],{},"Выше мы только что рассмотрели идеальную хеш-функцию. Она связывает товар точно с отдельной позицией массива.\nВ реальности такого идеального однозначного сопоставления, скорее всего, не получится. Товарам придётся соседствовать.\nВ одной позиции будут находиться несколько товаров, а другие позиции останутся пустыми. Эту ситуацию мы обсудим ниже в разделе о коллизиях.\nЕщё взаимно-однозначное связывание называют инъективной функцией.",[406,533,534],{},"Вероятно хеш-таблицы станут самой полезной из сложных структур данных, с которой вы познакомитесь.\nОни также известны под другими названиями: \"ассоциативные массивы\", \"словари\", \"отображения\", \"хеш-карты\", или просто \"хеши\".\nПомните описание массивов и связанных списков? Обращение к элементу массива происходит мгновенно.\nА хеш-таблицы используют массивы для хранения данных, поэтому при обращении к элементам они не уступают массивам.",[406,536,537,538,541],{},"Ассоциативный массив — абстрактный тип данных, с помощью которого хранятся пары «ключ-значение».\nВ разных языках ему соответствуют разные типы данных.\nВ Python — это Dictionary, т.е. Словарь (",[410,539,540],{"href":227},"что такое словарь Python","), в других языках:",[491,543,544,547,550,553],{},[494,545,546],{},"Ruby — Hash",[494,548,549],{},"Lua — Table",[494,551,552],{},"JavaScript — Object",[494,554,555],{},"Elixir\u002FJava — Map",[406,557,558,559,563],{},"Ассоциативные массивы популярны в прикладном программировании.\nС их помощью удобно представлять составные данные, содержащие множество различных параметров.\nВ обычном индексированном массиве значения расположены по индексам, а значит его можно положить в память «как есть».\nС ассоциативными массивами все работает по-другому.\nУ них нет индексов, которые бы могли определить порядок — значит, и нет простого способа добраться до значений.\nДля реализации ассоциативных массивов часто используют специальную структуру данных — ",[560,561,562],"strong",{},"хеш-таблицу",".\nХеш-таблица позволяет организовать данные ассоциативного массива удобным для хранения способом.\nДля этого хеш-таблица использует индексированный массив и функцию для хеширования ключей.\nПри этом хеш-таблица — это не просто способ размещать данные в памяти, она включает в себя логику.\nПосмотрим, как ассоциативные массивы устроены внутри(они же хеш-таблицы).\nСкорее всего, вам никогда не придётся заниматься реализацией ассоциативных массивов или хеш-таблиц самостоятельно.\nВ любом приличном современном языке программирования высокого уровня существует их реализация.\nВ Python хеш-таблицы ещё называются словарями. Новая хеш-таблица задаётся пустыми фигурными скобками.\nРазберём подобный простой код на Python:",[565,566,571],"pre",{"className":567,"code":568,"language":569,"meta":570,"style":570},"language-python shiki shiki-themes github-light","book = {} # book[\"key\"] = \"value\"\n","python","",[572,573,574],"code",{"__ignoreMap":570},[575,576,579,583,587,590],"span",{"class":577,"line":578},"line",1,[575,580,582],{"class":581},"sgsFI","book ",[575,584,586],{"class":585},"sD7c4","=",[575,588,589],{"class":581}," {} ",[575,591,593],{"class":592},"sAwPA","# book[\"key\"] = \"value\"\n",[406,595,596,599],{},[572,597,598],{},"book"," – это новая хеш-таблица. Добавим в неё несколько цен:",[565,601,603],{"className":567,"code":602,"language":569,"meta":570,"style":570},"book[\"яблоки\"] = 57.5\nbook[\"молоко\"] = 78.9\nbook[\"хлеб\"] = 52.5\nprint(book)\n# {'яблоки': 57.5, 'молоко': 78.9, 'хлеб': 52.5}\n",[572,604,605,623,638,653,662],{"__ignoreMap":570},[575,606,607,610,614,617,619],{"class":577,"line":578},[575,608,609],{"class":581},"book[",[575,611,613],{"class":612},"sYBdl","\"яблоки\"",[575,615,616],{"class":581},"] ",[575,618,586],{"class":585},[575,620,622],{"class":621},"sYu0t"," 57.5\n",[575,624,626,628,631,633,635],{"class":577,"line":625},2,[575,627,609],{"class":581},[575,629,630],{"class":612},"\"молоко\"",[575,632,616],{"class":581},[575,634,586],{"class":585},[575,636,637],{"class":621}," 78.9\n",[575,639,641,643,646,648,650],{"class":577,"line":640},3,[575,642,609],{"class":581},[575,644,645],{"class":612},"\"хлеб\"",[575,647,616],{"class":581},[575,649,586],{"class":585},[575,651,652],{"class":621}," 52.5\n",[575,654,656,659],{"class":577,"line":655},4,[575,657,658],{"class":621},"print",[575,660,661],{"class":581},"(book)\n",[575,663,665],{"class":577,"line":664},5,[575,666,667],{"class":592},"# {'яблоки': 57.5, 'молоко': 78.9, 'хлеб': 52.5}\n",[406,669,670],{},"Пока всё просто! А теперь запросим цену для яблок.",[565,672,674],{"className":567,"code":673,"language":569,"meta":570,"style":570},"print(book[\"яблоки\"]) # => 57.5 - цена\n",[572,675,676],{"__ignoreMap":570},[575,677,678,680,683,685,688],{"class":577,"line":578},[575,679,658],{"class":621},[575,681,682],{"class":581},"(book[",[575,684,613],{"class":612},[575,686,687],{"class":581},"]) ",[575,689,690],{"class":592},"# => 57.5 - цена\n",[406,692,693],{},"Хеш-таблица состоит из ключей и значений. В хеше book имена продуктов являются ключами, а цены – значениями.\nХеш-таблица связывает ключи со значениями.\nОчень важно, чтобы хеш-функции в хеш-таблицах были последовательными, то есть неизменно возвращали один и тот же результат для одинаковых входных данных.\nЕсли это условие будет нарушено, вы не сможете найти свой элемент после того, как он будет помещён в хеш-таблицу!",[695,696],"card-collapsible-num-answers",{":isAnswers":697,":isList":698,":startOl":699,"isText":700,"title":701},"[\"Функция последовательна.\",\"Функция непоследовательна.\",\"Функция непоследовательна.\",\"Функция последовательна.\"]","[\"f(x) = 1 – возвращает 1 для любых входных значений\",\"f(x) = random.random() – возвращает случайное число\",\"f(x) = next_empty_slot() – возвращает индекс следующего пустого элемента в хеш-таблице\",\"f(x) = len(x) – возвращает длину полученной строки\"]","1","Какие из следующих функций являются последовательными?","УПРАЖНЕНИЯ",[483,703,705],{"id":704},"что-такое-хеширование","Что такое хеширование",[406,707,708],{},"Любая операция внутри хеш-таблицы начинается с того, что ключ каким-то образом преобразуется в индекс обычного массива.\nДля получения индекса из ключа нужно выполнить два действия:",[491,710,711,714],{},[494,712,713],{},"Найти хеш, то есть хэшировать ключ",[494,715,716],{},"Привести ключ к индексу — например, через остаток от деления",[406,718,719,722,723,726,727,730,731,525],{},[560,720,721],{},"Хеширование"," — операция, которая преобразует любые входные данные в строку или число фиксированной длины.\nФункция, реализующая алгоритм преобразования, называется ",[518,724,725],{},"«хеш-функцией»",".\nПри этом результат хеширования называют ",[518,728,729],{},"«хешем»"," или ",[518,732,733],{},"«хеш-суммой»",[406,735,736],{},"Наиболее известны CRC32, MD5, SHA и много других типов хеширования:",[565,738,740],{"className":567,"code":739,"language":569,"meta":570,"style":570},"# В Python есть библиотека zlib, содержащая алгоритм хеширования crc32\n# Этот алгоритм удобен для наглядности\nimport zlib\n\n# Любые данные, которые мы хотим хешировать, представляются в виде байтовой строки\ndata = b\"Hello, python!\"\nhash = zlib.crc32(data)\n\n# Хеш всегда одинаковый для одних и тех же данных\nprint(hash)  # => 3159842700\n",[572,741,742,747,752,760,766,771,785,797,802,808],{"__ignoreMap":570},[575,743,744],{"class":577,"line":578},[575,745,746],{"class":592},"# В Python есть библиотека zlib, содержащая алгоритм хеширования crc32\n",[575,748,749],{"class":577,"line":625},[575,750,751],{"class":592},"# Этот алгоритм удобен для наглядности\n",[575,753,754,757],{"class":577,"line":640},[575,755,756],{"class":585},"import",[575,758,759],{"class":581}," zlib\n",[575,761,762],{"class":577,"line":655},[575,763,765],{"emptyLinePlaceholder":764},true,"\n",[575,767,768],{"class":577,"line":664},[575,769,770],{"class":592},"# Любые данные, которые мы хотим хешировать, представляются в виде байтовой строки\n",[575,772,774,777,779,782],{"class":577,"line":773},6,[575,775,776],{"class":581},"data ",[575,778,586],{"class":585},[575,780,781],{"class":585}," b",[575,783,784],{"class":612},"\"Hello, python!\"\n",[575,786,788,791,794],{"class":577,"line":787},7,[575,789,790],{"class":621},"hash",[575,792,793],{"class":585}," =",[575,795,796],{"class":581}," zlib.crc32(data)\n",[575,798,800],{"class":577,"line":799},8,[575,801,765],{"emptyLinePlaceholder":764},[575,803,805],{"class":577,"line":804},9,[575,806,807],{"class":592},"# Хеш всегда одинаковый для одних и тех же данных\n",[575,809,811,813,816,818,821],{"class":577,"line":810},10,[575,812,658],{"class":621},[575,814,815],{"class":581},"(",[575,817,790],{"class":621},[575,819,820],{"class":581},")  ",[575,822,823],{"class":592},"# => 3159842700\n",[406,825,826],{},"С хешированием мы встречаемся в разработке.\nНапример, идентификатор commit в git d7834a94 — это хеш, полученный в результате хеширования данных \"коммита\".",[406,828,829],{},"При записи в хеш-таблицу сначала нужно получить хеш.\nЗатем его можно преобразовать в индекс массива — например, вычислить остаток от деления:",[565,831,833],{"className":567,"code":832,"language":569,"meta":570,"style":570},"# Это делается для того, чтобы индексы не были слишком большими\n# Чем больше размер массива, тем больше памяти он занимает\nindex = abs(hash) % 1000  # по модулю\nprint(index)  # => 700\n",[572,834,835,840,845,871],{"__ignoreMap":570},[575,836,837],{"class":577,"line":578},[575,838,839],{"class":592},"# Это делается для того, чтобы индексы не были слишком большими\n",[575,841,842],{"class":577,"line":625},[575,843,844],{"class":592},"# Чем больше размер массива, тем больше памяти он занимает\n",[575,846,847,850,852,855,857,859,862,865,868],{"class":577,"line":640},[575,848,849],{"class":581},"index ",[575,851,586],{"class":585},[575,853,854],{"class":621}," abs",[575,856,815],{"class":581},[575,858,790],{"class":621},[575,860,861],{"class":581},") ",[575,863,864],{"class":585},"%",[575,866,867],{"class":621}," 1000",[575,869,870],{"class":592},"  # по модулю\n",[575,872,873,875,878],{"class":577,"line":655},[575,874,658],{"class":621},[575,876,877],{"class":581},"(index)  ",[575,879,880],{"class":592},"# => 700\n",[406,882,883],{},[884,885],"img",{"alt":886,"src":887},"Пример использования хеш-функции","\u002Fimages\u002Fblog\u002Fpython\u002Fst20\u002Fimg1.png",[889,890,892],"h4",{"id":891},"как-хеширование-работает-изнутри","Как хеширование работает изнутри",[406,894,895],{},"Рассмотрим, как работает добавление нового значения в ассоциативный массив.\nНапомним, в Python он представлен типом данных Dictionary. Напишем такой код:",[565,897,899],{"className":567,"code":898,"language":569,"meta":570,"style":570},"data = {}\ndata[\"key\"] = \"value\"\n",[572,900,901,910],{"__ignoreMap":570},[575,902,903,905,907],{"class":577,"line":578},[575,904,776],{"class":581},[575,906,586],{"class":585},[575,908,909],{"class":581}," {}\n",[575,911,912,915,918,920,922],{"class":577,"line":625},[575,913,914],{"class":581},"data[",[575,916,917],{"class":612},"\"key\"",[575,919,616],{"class":581},[575,921,586],{"class":585},[575,923,924],{"class":612}," \"value\"\n",[406,926,927],{},"Такой простой код запускает целый сложный процесс.\nДля простоты рассмотрим его на Python, хотя в реальности все это происходит на более низком уровне.\nОпишем процесс хеширования без деталей и с упрощенным кодом.",[929,930,931],"ol",{},[494,932,933],{},"Мы создаем ассоциативный массив. Внутри интерпретатора происходит инициализация индексированного массива:",[565,935,937],{"className":567,"code":936,"language":569,"meta":570,"style":570},"internal = [] \n",[572,938,939],{"__ignoreMap":570},[575,940,941,944,946],{"class":577,"line":578},[575,942,943],{"class":581},"internal ",[575,945,586],{"class":585},[575,947,948],{"class":581}," []\n",[929,950,951],{"start":625},[494,952,953],{},"Далее мы присваиваем значение:",[565,955,957],{"className":567,"code":956,"language":569,"meta":570,"style":570},"data['key'] = \"value\" \n",[572,958,959],{"__ignoreMap":570},[575,960,961,963,966,968,970],{"class":577,"line":578},[575,962,914],{"class":581},[575,964,965],{"class":612},"'key'",[575,967,616],{"class":581},[575,969,586],{"class":585},[575,971,924],{"class":612},[929,973,974],{"start":640},[494,975,976],{},"Затем интерпретатор хэширует ключ. Результатом хеширования становится число:",[565,978,980],{"className":567,"code":979,"language":569,"meta":570,"style":570},"hash = zlib.crc32(b'key') \n",[572,981,982],{"__ignoreMap":570},[575,983,984,986,988,991,994,996],{"class":577,"line":578},[575,985,790],{"class":621},[575,987,793],{"class":585},[575,989,990],{"class":581}," zlib.crc32(",[575,992,993],{"class":585},"b",[575,995,965],{"class":612},[575,997,998],{"class":581},")\n",[929,1000,1001],{"start":655},[494,1002,1003],{},"Далее интерпретатор берет число из предыдущего шага и преобразует его в индекс массива:",[565,1005,1007],{"className":567,"code":1006,"language":569,"meta":570,"style":570},"index = abs(hash) % 1000\n",[572,1008,1009],{"__ignoreMap":570},[575,1010,1011,1013,1015,1017,1019,1021,1023,1025],{"class":577,"line":578},[575,1012,849],{"class":581},[575,1014,586],{"class":585},[575,1016,854],{"class":621},[575,1018,815],{"class":581},[575,1020,790],{"class":621},[575,1022,861],{"class":581},[575,1024,864],{"class":585},[575,1026,1027],{"class":621}," 1000\n",[929,1029,1030],{"start":664},[494,1031,1032],{},"В конце интерпретатор ищет по индексу значение внутреннего индексированного массива и записывает его в еще один массив.\nПервым элементом нового массива становится ключ 'key', а вторым — значение 'value':",[565,1034,1036],{"className":567,"code":1035,"language":569,"meta":570,"style":570},"internal[index] = [\"key\", \"value\"] \n",[572,1037,1038],{"__ignoreMap":570},[575,1039,1040,1043,1045,1048,1050,1053,1056],{"class":577,"line":578},[575,1041,1042],{"class":581},"internal[index] ",[575,1044,586],{"class":585},[575,1046,1047],{"class":581}," [",[575,1049,917],{"class":612},[575,1051,1052],{"class":581},", ",[575,1054,1055],{"class":612},"\"value\"",[575,1057,1058],{"class":581},"]\n",[406,1060,1061],{},"Теперь посмотрим, как работает чтение данных:",[565,1063,1065],{"className":567,"code":1064,"language":569,"meta":570,"style":570},"data = {}\ndata[\"key\"] = \"value\"\nprint(data[\"key\"])  # => \"value\"\n",[572,1066,1067,1075,1087],{"__ignoreMap":570},[575,1068,1069,1071,1073],{"class":577,"line":578},[575,1070,776],{"class":581},[575,1072,586],{"class":585},[575,1074,909],{"class":581},[575,1076,1077,1079,1081,1083,1085],{"class":577,"line":625},[575,1078,914],{"class":581},[575,1080,917],{"class":612},[575,1082,616],{"class":581},[575,1084,586],{"class":585},[575,1086,924],{"class":612},[575,1088,1089,1091,1094,1096,1099],{"class":577,"line":640},[575,1090,658],{"class":621},[575,1092,1093],{"class":581},"(data[",[575,1095,917],{"class":612},[575,1097,1098],{"class":581},"])  ",[575,1100,1101],{"class":592},"# => \"value\"\n",[406,1103,1104],{},"Разберем, как этот код работает изнутри:",[929,1106,1107],{},[494,1108,1109],{},"Интерпретатор хеширует ключ. Результатом хеширования становится число:",[565,1111,1112],{"className":567,"code":979,"language":569,"meta":570,"style":570},[572,1113,1114],{"__ignoreMap":570},[575,1115,1116,1118,1120,1122,1124,1126],{"class":577,"line":578},[575,1117,790],{"class":621},[575,1119,793],{"class":585},[575,1121,990],{"class":581},[575,1123,993],{"class":585},[575,1125,965],{"class":612},[575,1127,998],{"class":581},[929,1129,1130],{"start":625},[494,1131,1132],{},"Число, полученное на предыдущем шаге, преобразуется в индекс массива:",[565,1134,1136],{"className":567,"code":1135,"language":569,"meta":570,"style":570},"index = abs(hash % 1000)\n",[572,1137,1138],{"__ignoreMap":570},[575,1139,1140,1142,1144,1146,1148,1150,1153,1155],{"class":577,"line":578},[575,1141,849],{"class":581},[575,1143,586],{"class":585},[575,1145,854],{"class":621},[575,1147,815],{"class":581},[575,1149,790],{"class":621},[575,1151,1152],{"class":585}," %",[575,1154,867],{"class":621},[575,1156,998],{"class":581},[929,1158,1159],{"start":640},[494,1160,1161],{},"Если индекс существует, то интерпретатор извлекает массив и возвращает его наружу:",[565,1163,1165],{"className":567,"code":1164,"language":569,"meta":570,"style":570},"return internal[index] # ['key', 'value']\n",[572,1166,1167],{"__ignoreMap":570},[575,1168,1169,1172,1175],{"class":577,"line":578},[575,1170,1171],{"class":585},"return",[575,1173,1174],{"class":581}," internal[index] ",[575,1176,1177],{"class":592},"# ['key', 'value']\n",[406,1179,1180],{},"В следующем разделе приведены примеры использования хеш-таблиц.",[483,1182,1184],{"id":1183},"примеры-использования-хеш-таблиц","Примеры использования хеш-таблиц",[406,1186,1187],{},"Хеш-таблицы повсеместно используют на практике. Рассмотрим некоторые примеры.",[889,1189,1191],{"id":1190},"хеш-таблица-для-поиска","Хеш-таблица для поиска",[406,1193,1194],{},"В смартфоне есть удобная встроенная телефонная книга. С каждым именем связывается номер телефона.\nПредположим, вы хотите построить такую телефонную книгу. Имена людей в этой книге связываются с номерами.\nТелефонная книга должна поддерживать следующие функции:",[491,1196,1197,1200],{},[494,1198,1199],{},"добавление имени человека и номера телефона, связанного с этим именем;",[494,1201,1202],{},"получение номера телефона, связанного с введенным именем.",[406,1204,1205],{},"Такая задача идеально подходит для хеш-таблиц! Хеш-таблицы отлично работают, когда вы хотите:",[491,1207,1208,1211],{},[494,1209,1210],{},"создать связь, отображающую один объект на другой;",[494,1212,1213],{},"найти значение в списке.",[406,1215,1216],{},"Построить телефонную книгу, в общем-то, несложно. Начнём с создания хеш-таблицы:",[565,1218,1220],{"className":567,"code":1219,"language":569,"meta":570,"style":570},"phone_book = {}\n",[572,1221,1222],{"__ignoreMap":570},[575,1223,1224,1227,1229],{"class":577,"line":578},[575,1225,1226],{"class":581},"phone_book ",[575,1228,586],{"class":585},[575,1230,909],{"class":581},[406,1232,1233],{},"Добавим в телефонную книгу несколько номеров:",[565,1235,1237],{"className":567,"code":1236,"language":569,"meta":570,"style":570},"phone_book[\"Иван\"] = 8654329\nphone_book[\"Саша\"] = 8656654\nphone_book[\"Маша\"] = 8658321\n",[572,1238,1239,1254,1268],{"__ignoreMap":570},[575,1240,1241,1244,1247,1249,1251],{"class":577,"line":578},[575,1242,1243],{"class":581},"phone_book[",[575,1245,1246],{"class":612},"\"Иван\"",[575,1248,616],{"class":581},[575,1250,586],{"class":585},[575,1252,1253],{"class":621}," 8654329\n",[575,1255,1256,1258,1261,1263,1265],{"class":577,"line":625},[575,1257,1243],{"class":581},[575,1259,1260],{"class":612},"\"Саша\"",[575,1262,616],{"class":581},[575,1264,586],{"class":585},[575,1266,1267],{"class":621}," 8656654\n",[575,1269,1270,1272,1275,1277,1279],{"class":577,"line":640},[575,1271,1243],{"class":581},[575,1273,1274],{"class":612},"\"Маша\"",[575,1276,616],{"class":581},[575,1278,586],{"class":585},[575,1280,1281],{"class":621}," 8658321\n",[406,1283,1284],{},"Теперь предположим, что вы хотите найти номер телефона Ивана. Просто передайте ключ хешу:",[565,1286,1288],{"className":567,"code":1287,"language":569,"meta":570,"style":570},"print(phone_book[\"Иван\"]) # => 8654329\n",[572,1289,1290],{"__ignoreMap":570},[575,1291,1292,1294,1297,1299,1301],{"class":577,"line":578},[575,1293,658],{"class":621},[575,1295,1296],{"class":581},"(phone_book[",[575,1298,1246],{"class":612},[575,1300,687],{"class":581},[575,1302,1303],{"class":592},"# => 8654329\n",[406,1305,1306],{},"Представьте, то же самое пришлось бы реализовывать через массив. Как бы вы это сделали?\nХеш-таблицы упрощают моделирование отношений между объектами.\nХеш-таблицы используются для поиска соответствий в гораздо большем масштабе.\nНапример, вы хотите перейти на веб-сайт – допустим, ashtana.ru\nВаш компьютер должен преобразовать символьное имя ashtana.ru в IP-адрес:\nashtana.ru — 216.198.79.1",[406,1308,1309],{},"Для любого веб-сайта его имя преобразуется в IP-адрес:\ngoogle.com — 142.250.185.238\ndzen.ru — 83.222.28.15\nvk.com — 87.240.137.164",[406,1311,1312,1313,1316],{},"Связать символьное имя с IP-адресом? Идеальная задача для хеш-таблиц! Этот процесс называется ",[518,1314,1315],{},"преобразованием DNS",".\nХеш-таблицы — всего лишь один из способов реализации такой функциональности.\nНа компьютерах существует кэш DNS, в котором хранятся подобные сопоставления для недавно посещенных сайтов.",[889,1318,1320],{"id":1319},"исключение-дубликатов","Исключение дубликатов",[406,1322,1323],{},"Предположим, вы проводите голосование. Естественно, каждый голосующий может проголосовать только один раз.\nКак проверить, что он не голосовал повторно? Когда человек приходит голосовать, вы узнаёте его полное имя, а затем проверяете по списку уже проголосовавших.\nЕсли имя входит в список, значит, этот человек уже проголосовал! В противном случае вы добавляете имя в список и разрешаете ему проголосовать.\nДалее предположим, что желающих проголосовать много и список уже проголосовавших достаточно велик.\nКаждый раз, когда кто-то приходит голосовать, вы вынуждены просматривать этот гигантский список и проверять, голосовал ли человек или нет.\nОднако, существует более эффективное решение: воспользоваться хешем!\nСначала создадим хеш-таблицу для хранения информации об уже проголосовавших людях:",[565,1325,1327],{"className":567,"code":1326,"language":569,"meta":570,"style":570},"voted = {}\n",[572,1328,1329],{"__ignoreMap":570},[575,1330,1331,1334,1336],{"class":577,"line":578},[575,1332,1333],{"class":581},"voted ",[575,1335,586],{"class":585},[575,1337,909],{"class":581},[406,1339,1340],{},"Когда кто-то приходит голосовать, проверьте, присутствует ли его имя в хеше:",[565,1342,1344],{"className":567,"code":1343,"language":569,"meta":570,"style":570},"vote = \"Александр Сергеевич Пушкин\" in voted\n",[572,1345,1346],{"__ignoreMap":570},[575,1347,1348,1351,1353,1356,1359],{"class":577,"line":578},[575,1349,1350],{"class":581},"vote ",[575,1352,586],{"class":585},[575,1354,1355],{"class":612}," \"Александр Сергеевич Пушкин\"",[575,1357,1358],{"class":585}," in",[575,1360,1361],{"class":581}," voted\n",[406,1363,1364,1365,1368],{},"Переменная ",[572,1366,1367],{},"vote"," принимает значение True, если такой ключ \"Александр Сергеевич Пушкин\" есть в хеш-таблице.\nВ противном случае она принимает значение False. С помощью этой функции можно проверить, голосовал ли человек ранее или нет!",[406,1370,1371],{},"Примерный код может выглядеть так:",[565,1373,1375],{"className":567,"code":1374,"language":569,"meta":570,"style":570},"voted = {}\n\ndef check_voter(name):\n  if name in voted:\n    print(\"Уже голосовал!\")\n  else:\n    voted[name] = True\n    print(\"Допустить к голосованию!\")\n",[572,1376,1377,1385,1389,1401,1415,1427,1435,1445],{"__ignoreMap":570},[575,1378,1379,1381,1383],{"class":577,"line":578},[575,1380,1333],{"class":581},[575,1382,586],{"class":585},[575,1384,909],{"class":581},[575,1386,1387],{"class":577,"line":625},[575,1388,765],{"emptyLinePlaceholder":764},[575,1390,1391,1394,1398],{"class":577,"line":640},[575,1392,1393],{"class":585},"def",[575,1395,1397],{"class":1396},"s7eDp"," check_voter",[575,1399,1400],{"class":581},"(name):\n",[575,1402,1403,1406,1409,1412],{"class":577,"line":655},[575,1404,1405],{"class":585},"  if",[575,1407,1408],{"class":581}," name ",[575,1410,1411],{"class":585},"in",[575,1413,1414],{"class":581}," voted:\n",[575,1416,1417,1420,1422,1425],{"class":577,"line":664},[575,1418,1419],{"class":621},"    print",[575,1421,815],{"class":581},[575,1423,1424],{"class":612},"\"Уже голосовал!\"",[575,1426,998],{"class":581},[575,1428,1429,1432],{"class":577,"line":773},[575,1430,1431],{"class":585},"  else",[575,1433,1434],{"class":581},":\n",[575,1436,1437,1440,1442],{"class":577,"line":787},[575,1438,1439],{"class":581},"    voted[name] ",[575,1441,586],{"class":585},[575,1443,1444],{"class":621}," True\n",[575,1446,1447,1449,1451,1454],{"class":577,"line":799},[575,1448,1419],{"class":621},[575,1450,815],{"class":581},[575,1452,1453],{"class":612},"\"Допустить к голосованию!\"",[575,1455,998],{"class":581},[406,1457,1458],{},"Протестируем на нескольких примерах:",[565,1460,1462],{"className":567,"code":1461,"language":569,"meta":570,"style":570},"check_voted(\"Иван\") # Допустить к голосованию!\ncheck_voted(\"Алесандр\") # Допустить к голосованию!\ncheck_voted(\"Иван\") # Уже голосовал!\n",[572,1463,1464,1476,1487],{"__ignoreMap":570},[575,1465,1466,1469,1471,1473],{"class":577,"line":578},[575,1467,1468],{"class":581},"check_voted(",[575,1470,1246],{"class":612},[575,1472,861],{"class":581},[575,1474,1475],{"class":592},"# Допустить к голосованию!\n",[575,1477,1478,1480,1483,1485],{"class":577,"line":625},[575,1479,1468],{"class":581},[575,1481,1482],{"class":612},"\"Алесандр\"",[575,1484,861],{"class":581},[575,1486,1475],{"class":592},[575,1488,1489,1491,1493,1495],{"class":577,"line":640},[575,1490,1468],{"class":581},[575,1492,1246],{"class":612},[575,1494,861],{"class":581},[575,1496,1497],{"class":592},"# Уже голосовал!\n",[406,1499,1500],{},"Когда Иван голосует первый раз, программа разрешает ему проголосовать. Потом приходит Александр, который также допускается к голосованию.\nНо вдруг снова приходит Иван, чтобы проголосовать снова! И на этот раз у него ничего не получится!",[406,1502,1503],{},"Если бы имена проголосовавших хранились в списке, то выполнение функции со временем замедлилось бы, потому что функции пришлось бы проводить простой поиск по всему списку.\nНо имена хранятся в хеш-таблице, а она почти мгновенно сообщает, присутствует ли человек в списке голосовавших или нет.\nПроверка дубликатов происходит очень быстро!",[889,1505,1507],{"id":1506},"использование-хеш-таблицы-как-кэша","Использование хеш-таблицы как кэша",[406,1509,1510],{},"Последний пример: кэширование. Если вы создаёте веб-сайт, то вероятно, уже слышали о пользе кэширования.\nОбщая идея кэширования такова: допустим, вы заходите на сайт.",[929,1512,1513,1516,1519],{},[494,1514,1515],{},"Вы обращаетесь с запросом к серверу;",[494,1517,1518],{},"Сервер ненадолго задумывается, генерирует веб-страницу и отправляет её вам;",[494,1520,1521],{},"Вы получаете и просматриваете веб-страницу.",[406,1523,1524,1525,1528],{},"Например, VK сервер может собирать информацию о действиях всех ваших друзей, чтобы представить её вам.\nНа то, чтобы собрать всю информацию и представить её вам требуется пара секунд.\nСервер просто заранее сам вычисляет, запоминает, а когда вы делаете запрос просто выдаёт готовый ответ.\nТак работает механизм кэширования. Сайт просто запоминает данные заранее, и вместо того чтобы их пересчитывать, выдаёт сразу ответ пользователю.\nТакой механизм как ",[518,1526,1527],{},"кэширование"," обладает следующими преимуществами:",[491,1530,1531,1534],{},[494,1532,1533],{},"Вы получаете документ, например веб-страницу, намного быстрее, как и в том случае, когда вы заранее запомнили ответ на вопрос;",[494,1535,1536],{},"Серверу сайта с механизмом кэширования приходится выполнять меньше работы при очередном одинаковом запросе от пользователей.",[406,1538,1539],{},"Когда вы посещаете сайт у которого настроено кэширование, сервер сайта сначала проверяет, хранится ли страница в кэше.\nВот примерный псевдокод на Python как это может быть:",[565,1541,1543],{"className":567,"code":1542,"language":569,"meta":570,"style":570},"cache = {}\ndef get_page(url):\n  if url in cache:\n    return cache[url]\n  else:\n    data = get_data_from_server(url)\n    cache[url] = data\n    return data\n",[572,1544,1545,1554,1564,1576,1584,1590,1600,1610],{"__ignoreMap":570},[575,1546,1547,1550,1552],{"class":577,"line":578},[575,1548,1549],{"class":581},"cache ",[575,1551,586],{"class":585},[575,1553,909],{"class":581},[575,1555,1556,1558,1561],{"class":577,"line":625},[575,1557,1393],{"class":585},[575,1559,1560],{"class":1396}," get_page",[575,1562,1563],{"class":581},"(url):\n",[575,1565,1566,1568,1571,1573],{"class":577,"line":640},[575,1567,1405],{"class":585},[575,1569,1570],{"class":581}," url ",[575,1572,1411],{"class":585},[575,1574,1575],{"class":581}," cache:\n",[575,1577,1578,1581],{"class":577,"line":655},[575,1579,1580],{"class":585},"    return",[575,1582,1583],{"class":581}," cache[url]\n",[575,1585,1586,1588],{"class":577,"line":664},[575,1587,1431],{"class":585},[575,1589,1434],{"class":581},[575,1591,1592,1595,1597],{"class":577,"line":773},[575,1593,1594],{"class":581},"    data ",[575,1596,586],{"class":585},[575,1598,1599],{"class":581}," get_data_from_server(url)\n",[575,1601,1602,1605,1607],{"class":577,"line":787},[575,1603,1604],{"class":581},"    cache[url] ",[575,1606,586],{"class":585},[575,1608,1609],{"class":581}," data\n",[575,1611,1612,1614],{"class":577,"line":799},[575,1613,1580],{"class":585},[575,1615,1609],{"class":581},[406,1617,1618],{},"Такой сервер выполняет работу только в том случае, если URL не хранится в кэше. Однако перед тем, как возвращать данные, вы сохраняете их в кэше.\nКогда пользователь в следующий раз запросит тот же URL-адрес, данные(хорошо бы ещё проверять при условии, что они не изменились!) отправляются пользователю из кэша(вместо вычислений на сервере).",[401,1620],{":isList":1621,"title":1622,"isText":1623},"[\"Моделирование отношений между объектами;\",\"Устранение дубликатов;\",\"Кэширование\u002Fзапоминание данных вместо выполнения работы на сервере.\"]","ШПАРГАЛКА","Хеши хорошо подходят для решения следующих задач",[483,1625,1627],{"id":1626},"коллизии","Коллизии",[406,1629,1630],{},"Прежде чем понять какое быстродействие у хеш-таблиц, необходимо понять, что такое коллизия.\nКлючом в ассоциативном массиве или хеш-таблицы может быть абсолютно любая строка, любой длины и содержания.\nНо здесь есть одно противоречие:",[491,1632,1633,1636],{},[494,1634,1635],{},"Все возможные ключи — это бесконечное множество;",[494,1637,1638],{},"В качестве результата хеш-функция выдает строку фиксированной длины, то есть все выходные значения — это конечное множество.",[406,1640,1641],{},"Из этого факта следует, что не для всех входных данных найдется уникальный хеш.\nНа каком-то этапе могут появиться дубли: под одним хешем будут лежать несколько разных значений.",[406,1643,1644,1645,1648],{},"Такую ситуацию принято называть ",[518,1646,1647],{},"коллизией",". Есть несколько способов разрешения коллизий.\nКаждому способу соответствует свой тип хеш-таблицы:",[565,1650,1652],{"className":567,"code":1651,"language":569,"meta":570,"style":570},"# Пример коллизии\n# Хеш-функция возвращает одинаковый хеш для разных строчных данных\nimport zlib\nzlib.crc32(b\"aaaaa0.462031558722291\")  # 1938556049\nzlib.crc32(b\"aaaaa0.0585754039730588\")  # 1938556049\n",[572,1653,1654,1659,1664,1670,1685],{"__ignoreMap":570},[575,1655,1656],{"class":577,"line":578},[575,1657,1658],{"class":592},"# Пример коллизии\n",[575,1660,1661],{"class":577,"line":625},[575,1662,1663],{"class":592},"# Хеш-функция возвращает одинаковый хеш для разных строчных данных\n",[575,1665,1666,1668],{"class":577,"line":640},[575,1667,756],{"class":585},[575,1669,759],{"class":581},[575,1671,1672,1675,1677,1680,1682],{"class":577,"line":655},[575,1673,1674],{"class":581},"zlib.crc32(",[575,1676,993],{"class":585},[575,1678,1679],{"class":612},"\"aaaaa0.462031558722291\"",[575,1681,820],{"class":581},[575,1683,1684],{"class":592},"# 1938556049\n",[575,1686,1687,1689,1691,1694,1696],{"class":577,"line":664},[575,1688,1674],{"class":581},[575,1690,993],{"class":585},[575,1692,1693],{"class":612},"\"aaaaa0.0585754039730588\"",[575,1695,820],{"class":581},[575,1697,1684],{"class":592},[406,1699,1700,1701,1704],{},"Простейший способ разрешения коллизий — это ",[518,1702,1703],{},"открытая адресация",".\nОна предполагает последовательное перемещение по слотам хеш-таблицы в поисках первого свободного слота, куда значение будет записано.",[406,1706,1707],{},"Второй простейший способ разрешения коллизий выглядит так: если несколько \"ключей\" хеш-таблицы отображаются после хеш-функции на один элемент, то по этому адресу сначала создаётся связанный список, а затем оба элемента по которым происходит коллизия сохраняются в этот список.\nНапример, у нас в хеш-таблице строки \"апельсины\" и \"яблоки\", отображаются на один элемент после работы хш-функции, тогда в элементе хеш-таблицы создаётся связанный список.\nЕсли в дальнейшем потребуется узнать цену \"апельсинов\" или \"яблок\", работа пойдёт чуть медленнее так как провести поиск необходимо будет ещё и по связанному списку, чтобы найти уже в нём цену \"апельсинов\" или \"яблок\".\nЕсли связанный список мал, это не так страшно – поиск будет ограничен тремя или четырьмя элементами.\nНо если после работы хеш-функции все данные окажутся в одном связанном списке, то ситуация не лучше той, когда все элементы сразу бы хранились в связанном списке.\nИз этого следуют два вывода:",[491,1709,1710,1713],{},[494,1711,1712],{},"выбор хеш-функции действительно очень важен. В идеале хеш-функция должна распределять ключи по всему хешу – равномерно;",[494,1714,1715],{},"если связанные списки становятся слишком длинными, работа с хеш-таблицей сильно замедляется.",[406,1717,1718],{},"Хеш-функции играют важнейшую роль! Хорошая хеш-функция создаёт минимальное количество коллизий! Как выбрать хорошую хеш-функцию?",[483,1720,1722],{"id":1721},"быстродействие","Быстродействие",[406,1724,1725,1726,1729],{},"В среднем хеш-таблицы выполняют любые операции за время O(1). Время O(1) называется ",[518,1727,1728],{},"постоянным временем выполнения",".\nЭто время означает, что операции выполняются почти мгновенно, само время выполнения зависит только от того как его выдаст исполнитель операции и является постоянным независимо от размера хеш-таблицы.\nПри любом размере хеш-таблицы — 1 элемент или 1 миллиард элементов — выборка данных займёт одинаковое время.\nЕщё как пример постоянного времени выполнения: выборка элемента из массива по индексу.\nПри сравнении хеш-таблицы с массивами и списками получается, что хорошие хеш-таблицы не уступают в скорости массивам при получении данных.\nА при вставке и удалении они также быстры как связанные списки! Получается что они берут лучшее из этих обеих структур!\nНо в худшем же случае они медленно выполняют все операции! Поэтому важно избегать худших случаев при работе с хеш-таблицами.\nА для этого следует избегать коллизий. Для предотвращения коллизий необходимы:",[491,1731,1732,1735],{},[494,1733,1734],{},"Хорошая хеш-функция;",[494,1736,1737],{},"Низкий коэффициент заполнения хеш-таблицы.",[889,1739,1741],{"id":1740},"коэффициент-заполнения","Коэффициент заполнения",[406,1743,1744],{},"Коэффициент заполнения хеш-таблицы вычисляется по простой формуле: количество элементов в таблице разделить на общее всех элементов.",[406,1746,1747],{},"Хеш-таблицы используют массив для хранения данных, поэтому для вычисления коэффициента заполнения можно подсчитать количество заполненных элементов в массиве(количество элементов в массиве разделить на размер массива).",[406,1749,1750],{},"Предположим, в хеш-таблице нужно сохранить цены 100 товаров и хеш-таблица состоит из 100 элементов.\nВ лучшем случае каждому товару будет выделен отдельный элемент.\nКоэффициент заполнения этой хеш-таблицы тогда будет равен 1.\nА если хеш-таблица состоит всего из 50 элементов?\nТогда её коэффициент заполнения будет равен 2.\nВыделить под каждый товар отдельный элемент ни при каких условиях не удастся, потому что элементов попросту не хватит.\nКоэффициент заполнения больше 1 означает, что количество элементов превышает количество свободных для них мест.\nС ростом коэффициента заполнения размер хеш-таблицы нужно изменить. Хеш-таблицу необходимо расширить.\nРасширение начинается с создания массива большего размера. Обычно в таком случае создаётся массив вдвое большего размера.\nЗатем все элементы необходимо заново вставить в новую хеш-таблицу через её же хеш-функцию.\nС меньшим коэффициентом заполнения число коллизий также уменьшается!\nХорошее приближённое правило: расширять хеш-таблицу если коэффициент заполнения приближается к 0.7.\nНо ведь на изменение размеров может уйти много времени и и вычислительных ресурсов? Да, и поэтому изменение размера не должно происходить часто!\nВ среднем же хеш-таблицы работают за время O(1) даже с изменением размеров.",[889,1752,1754],{"id":1753},"хорошая-хеш-функция","Хорошая хеш-функция",[406,1756,1757,1758,1764],{},"Вот мы и добрались до финального понимания хорошей хеш-функции!\nХорошая хеш-функция должна обеспечивать равномерное распределение значений в хеш-таблице!\nПлохая хеш-функция создаёт скопления и порождает множество коллизий!\nКакую же хеш-функцию считать хорошей? Опять спросите вы.\nДумаю, нам никогда не придётся об этом беспокоиться — пусть об этом думают умные люди в тёмных кабинет Google, Yandex и т.п. компаний.\nЕсли вам действительно интересно, рассмотрите фукнцию например, ",[410,1759,1763],{"href":1760,"rel":1761},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fcityhash",[1762],"nofollow","CityHash",". Именно её использует Google Abseil.\nAbseil — это набор библиотек C++ с открытым исходным кодом, созданных на основе самых фундаментальных элементов внутренней кодовой базы Google.\nAbseil лежит в основе кода, который пишут в Google, поэтому если в ней используется такая хеш-функция как CityHash, можно быть уверенным, что это функция как минимум неплоха.\nСмело применяйте её для своей хеш-таблицы!",[406,1766,1767],{},"Очень важно, чтобы хеш-функция обеспечивала хорошее распределение! Она должна распределять значения как можно шире!\nХудший случай — хеш-функция, которая отображает все входные строки на одну позицию в хеш-таблице!",[406,1769,1770],{},"Предположим, имеются четыре хеш-функции, которые получают строки.",[929,1772,1773,1776,1779,1782],{},[494,1774,1775],{},"Функция возвращает 1 для любого входного значения.",[494,1777,1778],{},"Функция возвращает длину строки в качестве ключа хеш-таблицы.",[494,1780,1781],{},"Функция возвращает первый символ строки в качестве индекса. Таким образом, все строки, начинающиеся с \"а\", хешируются в одну позицию.",[494,1783,1784],{},"Функция сначала ставит в соответствие каждой букве простое число: a = 1, b = 2, c = 3 и т.д. Для строки хеш-функцией далее становится остаток от деления суммы всех значений на размер хеша. Например, если размер хеша равен 10, то для строки \"age\" будет вычислен индекс или ключ (1 + 7 + 5) % 10 = 13 % 10 = 3.",[695,1786],{":isAnswers":1787,":isList":1788,":startOl":1789,"isText":1790,"title":701},"[\"Хеш-функции 3 и 4 обеспечивают лучшее распределение чем 1 и 2.\",\"Хеш-функции 2 и 4 обеспечивают лучшее распределении чем 1 и 3.\",\"Хеш-функции 2, 3, 4 обеспечивают лучшее распредление чем 1.\"]","[\"Телефонная книга, в которой ключами являются имена, а значениями – номера телефонов. Задан следующий список имён: Иван, Пётр, Нина, Павел.\",\"Связь размера батареек с напряжением. Размеры батареек: A, AA, AAA, AAAA.\",\"Связь названий книг с именами авторов. Названия книг: \\\"Мышь\\\", \\\"Весёлый дом\\\", \\\"Хранитель\\\"\"]","5","В каком из примеров четырёх хеш-функций описанных выше будет хорошее распределение? Считайте что, хеш-таблица содержит 10 элементов.",[889,1792],{"id":570},[401,1794],{":isList":1795,"title":1622,"isText":1796},"[\"Хеш-таблица создаётся объединением хеш-функции с массивом;\",\"Коллизии максимально нежелательны. Необходимо сводить количество коллизий с помощью хорошей хеш-фукнции к минимуму;\",\"Хеш-таблицы обеспечивают очень быстрое выполнение поиска, вставки и удаления;\",\"Хеш-таблицы хорошо подходят для моделирования отношений между объектами;\",\"Как только коэффициент заполнения хеш-таблицы превышает 0.7, пора изменять размер хеш-таблицы;\",\"Хеш-таблицы можно применять для кэширования данных;\",\"Хеш-таблицы хорошо подходят для обнаружения дубликатов.\"]","Хеш-таблицы чрезвычайно полезны, потому что они обеспечивают высокую скорость операций и позволяют по-разному моделировать данные.",[406,1798,1799,1800,1803,1804,1807],{},"Попробуйте сами запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает.\nДля этого в ячейке с кодом нажмите клавиши на клавиатуре ",[560,1801,1802],{},"Shift+Enter"," или запустите код через ",[560,1805,1806],{},"кнопку Run"," по значку ▶.",[1809,1810],"jypiter",{},[1812,1813,1814],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":570,"searchDepth":625,"depth":664,"links":1816},[1817],{"id":399,"depth":625,"text":238,"children":1818},[1819,1820,1823,1828,1829],{"id":485,"depth":640,"text":486},{"id":704,"depth":640,"text":705,"children":1821},[1822],{"id":891,"depth":655,"text":892},{"id":1183,"depth":640,"text":1184,"children":1824},[1825,1826,1827],{"id":1190,"depth":655,"text":1191},{"id":1319,"depth":655,"text":1320},{"id":1506,"depth":655,"text":1507},{"id":1626,"depth":640,"text":1627},{"id":1721,"depth":640,"text":1722,"children":1830},[1831,1832,1833],{"id":1740,"depth":655,"text":1741},{"id":1753,"depth":655,"text":1754},{"id":570,"depth":655,"text":570},"2025-12-11","Как работает хеш‑функция. Устройство и практическое применение хеш‑таблиц. Коллизии в хеш-таблицах и их разрешение. Производительность и примеры хеш-функций.","md","images\u002Fblog\u002Fpython\u002Fst20\u002Fimg.png",{},41,20,{"title":238,"description":1835},"O0W80aPXY3n-O3ctCtAuUEkgCg6QKakO1v8kQE142CQ",[1844,1846],{"title":230,"path":231,"stem":232,"description":1845,"children":-1},"Синтаксис. Изменение множеств. Операции над множествами. Методы объектов множеств",{"title":242,"path":243,"stem":244,"description":1847,"children":-1},"Решето Эратосфена - алгоритм определения простых чисел",1780737509544]