[{"data":1,"prerenderedAt":1120},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fpython\u002Fst30":386,"\u002Fblog\u002Fpython\u002Fst30-surround":1115},[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":282,"author":388,"body":393,"date":1106,"description":1107,"extension":1108,"image":1109,"meta":1110,"minRead":1111,"navigation":519,"num":1112,"path":283,"seo":1113,"stem":284,"__hash__":1114},"python\u002Fblog\u002Fpython\u002Fst30.md",{"name":389,"avatar":390},"Штана Альберт Игоревич",{"src":391,"alt":392},"me.jpg","@ashtana",{"type":394,"value":395,"toc":1092},"minimark",[396,400,405,409,414,417,420,427,430,435,443,456,459,698,701,716,720,723,861,864,869,876,880,887,891,912,917,921,926,931,946,954,957,966,974,979,984,990,995,1000,1005,1010,1016,1022,1032,1049,1066,1073,1082,1084,1088],[397,398,282],"h2",{"id":399},"поиск-в-глубину",[401,402],"card-collapsible",{":isList":403,"title":404},"[\"Узнаете, что такое дерево и чем дерево отличается от графа.\",\"Освоите выполнения алгоритмов с деревьями.\",\"Реализуете алгоритм поиска в глубину DFS (Depth-First Search) и узнаете, чем он отличается от алгоритма поиска в ширину BFS(Breadth-First Search).\",\"Познакомитесь с кодом Хаффмана — алгоритмом сжатия, использующим деревья.\"]","Из этой статьи вы",[406,407,408],"p",{},"Что общего у алгоритмов сжатия и хранения информации в базе данных?\nВ их основе часто лежит дерево, выполняющее всю работу.\nДеревья составляют подмножество графов. Деревья стоит рассматривать отдельно, так как у них есть много специализированных разновидностей.\nНапример, в коде Хаффмана применяются бинарные деревья.\nМногие базы данных используют сбалансированные деревья(например B-деревья). Видов деревьев довольно много.\nЧтобы вам легче было разобраться в них далее будет описаны некоторые из них с необходимой терминологией и концепциями.",[410,411,413],"h3",{"id":412},"дерево","Дерево",[406,415,416],{},"Дерево — это разновидность графа. Более подробное определение дадим позже, а пока рассмотрим пример.",[406,418,419],{},"Как и граф, дерево состоит из узлов и рёбер.",[406,421,422],{},[423,424],"img",{"alt":425,"src":426},"Пример дерева","\u002Fimages\u002Fblog\u002Fpython\u002Fst30\u002Fimg_1.png",[406,428,429],{},"Мы будем работать с однокоренными деревьями.\nЭто означает, что у корневого дерева имеется один узел, от которого можно перейти к любому другому узлу.\nТак что говоря о дереве, я имею в виду корневое дерево.\nУ узлов могут быть дочерние узлы, а у дочерних узлов может быть родительский узел.\nВ дереве узлы имеют по крайней мере одного родителя.\nСуществует только один узел без родителя — это корневой узел.\nУзлы, не имеющие дочерних узлов, называются листовыми узлами (листьями).\nЕсли вы поняли, что такое корень, лист, родительский и дочерний узел, значит, можно читать дальше!",[431,432,434],"h4",{"id":433},"каталоги-файлов","Каталоги файлов",[406,436,437,438,442],{},"Так как дерево является разновидностью графа, к нему можно применить алгоритм работающий с графом.\n",[439,440,441],"a",{"href":275},"В предыдущей статье был рассмотрен алгоритм поиска в ширину.","\nПоиск в ширину можно использовать и с деревом.\nНапример, каталог файлов представляет собой дерево, с которым каждый кто работает за ПК сталкивается.\nПредставьте, что у вас есть некий каталог и по нему требуется вывести имена всех файлов в каталоге, включая все его подкаталоги.\nВ данном случае существует только один подкаталог. Тогда такую задачу можно решить поиск в ширину.\nэАлгоритм поиска в ширину можно использовать не только как инструмент собственно поиска.\nПоиск в ширину является также алгоритмом обхода: он посещает каждый узел дерева(\"обходит\" его).\nВ случае с выводом всех имён файлов в подкаталогах — это то что нужно!\nНам нужен алгоритм, который перейдёт до каждого файла в дереве и выведет его имя. Логика такая:",[444,445,446,450,453],"ol",{},[447,448,449],"li",{},"Посетить каждый узел в дереве.",[447,451,452],{},"Если узел является файлом, вывести его имя.",[447,454,455],{},"Если узел является каталогом, добавить его в очередь, чтобы затем поискать находящиеся в нём файлы.",[406,457,458],{},"Ниже приведён код реализации такой программы(он похож на код для поиска \"продавца яблок\" из прошлой статьи):",[460,461,466],"pre",{"className":462,"code":463,"language":464,"meta":465,"style":465},"language-python shiki shiki-themes github-light","from os import listdir\nfrom os.path import isfile, join\nfrom collection import deque\n\ndef print_file_names(dir):\n    # Очередь используется для отслеживания каталогов, в которых потом производится поиск\n    s_deque = deque()\n    s_deque.append(dir) \n    while s_deque: # Пока очередь не пуста нужно извлекать из неё каталог для проверки\n      dr = s_deque.popleft() # Извлечь каталог из очереди\n      for file in sorted(listdir(dr)): # Перебрать все файлы и каталоги в извлечённом каталоге\n        f_path = join(dr, file) # Формируем полный путь к файлу\n        if isfile(f_path): # Если файл значит выводим его имя \n          print(file)\n        else:\n          s_deque.append(f_path) # Если каталог то добавляем её в конец очереди для обхода\n\nprint_file_names(\"docs\") # Запуск в качестве примера для некоторого каталога docs\n","python","",[467,468,469,488,501,514,521,534,541,553,566,578,592,614,634,646,660,669,678,683],"code",{"__ignoreMap":465},[470,471,474,478,482,485],"span",{"class":472,"line":473},"line",1,[470,475,477],{"class":476},"sD7c4","from",[470,479,481],{"class":480},"sgsFI"," os ",[470,483,484],{"class":476},"import",[470,486,487],{"class":480}," listdir\n",[470,489,491,493,496,498],{"class":472,"line":490},2,[470,492,477],{"class":476},[470,494,495],{"class":480}," os.path ",[470,497,484],{"class":476},[470,499,500],{"class":480}," isfile, join\n",[470,502,504,506,509,511],{"class":472,"line":503},3,[470,505,477],{"class":476},[470,507,508],{"class":480}," collection ",[470,510,484],{"class":476},[470,512,513],{"class":480}," deque\n",[470,515,517],{"class":472,"line":516},4,[470,518,520],{"emptyLinePlaceholder":519},true,"\n",[470,522,524,527,531],{"class":472,"line":523},5,[470,525,526],{"class":476},"def",[470,528,530],{"class":529},"s7eDp"," print_file_names",[470,532,533],{"class":480},"(dir):\n",[470,535,537],{"class":472,"line":536},6,[470,538,540],{"class":539},"sAwPA","    # Очередь используется для отслеживания каталогов, в которых потом производится поиск\n",[470,542,544,547,550],{"class":472,"line":543},7,[470,545,546],{"class":480},"    s_deque ",[470,548,549],{"class":476},"=",[470,551,552],{"class":480}," deque()\n",[470,554,556,559,563],{"class":472,"line":555},8,[470,557,558],{"class":480},"    s_deque.append(",[470,560,562],{"class":561},"sYu0t","dir",[470,564,565],{"class":480},") \n",[470,567,569,572,575],{"class":472,"line":568},9,[470,570,571],{"class":476},"    while",[470,573,574],{"class":480}," s_deque: ",[470,576,577],{"class":539},"# Пока очередь не пуста нужно извлекать из неё каталог для проверки\n",[470,579,581,584,586,589],{"class":472,"line":580},10,[470,582,583],{"class":480},"      dr ",[470,585,549],{"class":476},[470,587,588],{"class":480}," s_deque.popleft() ",[470,590,591],{"class":539},"# Извлечь каталог из очереди\n",[470,593,595,598,602,605,608,611],{"class":472,"line":594},11,[470,596,597],{"class":476},"      for",[470,599,601],{"class":600},"sqxcx"," file",[470,603,604],{"class":476}," in",[470,606,607],{"class":561}," sorted",[470,609,610],{"class":480},"(listdir(dr)): ",[470,612,613],{"class":539},"# Перебрать все файлы и каталоги в извлечённом каталоге\n",[470,615,617,620,622,625,628,631],{"class":472,"line":616},12,[470,618,619],{"class":480},"        f_path ",[470,621,549],{"class":476},[470,623,624],{"class":480}," join(dr, ",[470,626,627],{"class":600},"file",[470,629,630],{"class":480},") ",[470,632,633],{"class":539},"# Формируем полный путь к файлу\n",[470,635,637,640,643],{"class":472,"line":636},13,[470,638,639],{"class":476},"        if",[470,641,642],{"class":480}," isfile(f_path): ",[470,644,645],{"class":539},"# Если файл значит выводим его имя \n",[470,647,649,652,655,657],{"class":472,"line":648},14,[470,650,651],{"class":561},"          print",[470,653,654],{"class":480},"(",[470,656,627],{"class":600},[470,658,659],{"class":480},")\n",[470,661,663,666],{"class":472,"line":662},15,[470,664,665],{"class":476},"        else",[470,667,668],{"class":480},":\n",[470,670,672,675],{"class":472,"line":671},16,[470,673,674],{"class":480},"          s_deque.append(f_path) ",[470,676,677],{"class":539},"# Если каталог то добавляем её в конец очереди для обхода\n",[470,679,681],{"class":472,"line":680},17,[470,682,520],{"emptyLinePlaceholder":519},[470,684,686,689,693,695],{"class":472,"line":685},18,[470,687,688],{"class":480},"print_file_names(",[470,690,692],{"class":691},"sYBdl","\"docs\"",[470,694,630],{"class":480},[470,696,697],{"class":539},"# Запуск в качестве примера для некоторого каталога docs\n",[406,699,700],{},"В очереди хранится информация о том, в каких ещё каталогах нужно провести \"обход\" и найти имена файлов.\nВ этом примере присутствует отличие от примера поиска в ширину из прошлой статьи.\nВ примере из статьи про поиск в ширину про \"продавца яблок\" необходимо было следить, проводился ли уже поиск с конкретным человеком(элементом поиска).\nЗдесь этого делать не нужно. В деревьях нет циклов, и в данном случае у каждого узла только один родитель в виде каталога.\nМы здесь не рассматриваем и не сможем случайно ввести программу в бесконечный цикл при обходе подкаталогов, поэтому и нет необходимости отслеживать, в каких каталогах уже был поиск.\nЭто важный вывод который стоит использовать: в деревьях не бывает циклов.",[702,703,704],"blockquote",{},[406,705,706,707,715],{},"О символических ссылках. Пару слов для тех, кто не знает. Создание символических ссылок открывает возможность создания циклов в каталогах.\nСимволическую ссылку можно создать двумя известными способами в Linux или macOS командой: ln -s \u003Cпуть каталога> \u003Cпуть каталога>\nДля Windows это команда: mklink \u002Fd \u003Cпуть каталога> \u003Cпуть каталога>\nПолучается, что с помощью символической ссылки можно по двум путям попадать фактически в один каталог с файлами.\nКогда система или приложение обращается к символической ссылке, она автоматически перенаправляет запрос к целевому файлу или директории, указанному в ссылке.\nПри представлении такого каталога в виде дерева — каталог уже не будет являться деревом! В примере выше мы такую ситуацию не рассматриваем.\nК слову Python достаточно сообразителен поэтому в бесконечный цикл мы с символическими ссылками не попадаем а получаем в программе ошибку:\n",[708,709,710,711,714],"em",{},"OSError: ",[470,712,713],{},"Errno 62"," Too many levels of symbolic links"," — т.е. слишком много уровней символических ссылок.",[410,717,719],{"id":718},"реализация-алгоритма","Реализация алгоритма",[406,721,722],{},"Обойдём каталог файлов на этот раз рекурсивно:",[460,724,726],{"className":462,"code":725,"language":464,"meta":465,"style":465},"from os import listdir\nfrom os.path import isfile, join\n\ndef print_file_names(dir):\n    # Перебрать все файлы и подкаталоги\n    for file in sorted(listdir(dir)):\n        f_path = join(dir, file) # Формируем полный путь к файлу\n        if isfile(f_path): \n            # Если файл значит выводим его имя \n            print(file)\n        else:\n            # Если каталог то вызываем функцию рекурсивно\n            # Чтобы снова провести обход файлов в подкаталоге как в основном каталоге поиска\n            print_file_names(fullpath)\n\nprint_file_names(\"pics\")\n",[467,727,728,738,748,752,760,765,784,804,811,816,827,833,838,843,848,852],{"__ignoreMap":465},[470,729,730,732,734,736],{"class":472,"line":473},[470,731,477],{"class":476},[470,733,481],{"class":480},[470,735,484],{"class":476},[470,737,487],{"class":480},[470,739,740,742,744,746],{"class":472,"line":490},[470,741,477],{"class":476},[470,743,495],{"class":480},[470,745,484],{"class":476},[470,747,500],{"class":480},[470,749,750],{"class":472,"line":503},[470,751,520],{"emptyLinePlaceholder":519},[470,753,754,756,758],{"class":472,"line":516},[470,755,526],{"class":476},[470,757,530],{"class":529},[470,759,533],{"class":480},[470,761,762],{"class":472,"line":523},[470,763,764],{"class":539},"    # Перебрать все файлы и подкаталоги\n",[470,766,767,770,772,774,776,779,781],{"class":472,"line":536},[470,768,769],{"class":476},"    for",[470,771,601],{"class":600},[470,773,604],{"class":476},[470,775,607],{"class":561},[470,777,778],{"class":480},"(listdir(",[470,780,562],{"class":561},[470,782,783],{"class":480},")):\n",[470,785,786,788,790,793,795,798,800,802],{"class":472,"line":543},[470,787,619],{"class":480},[470,789,549],{"class":476},[470,791,792],{"class":480}," join(",[470,794,562],{"class":561},[470,796,797],{"class":480},", ",[470,799,627],{"class":600},[470,801,630],{"class":480},[470,803,633],{"class":539},[470,805,806,808],{"class":472,"line":555},[470,807,639],{"class":476},[470,809,810],{"class":480}," isfile(f_path): \n",[470,812,813],{"class":472,"line":568},[470,814,815],{"class":539},"            # Если файл значит выводим его имя \n",[470,817,818,821,823,825],{"class":472,"line":580},[470,819,820],{"class":561},"            print",[470,822,654],{"class":480},[470,824,627],{"class":600},[470,826,659],{"class":480},[470,828,829,831],{"class":472,"line":594},[470,830,665],{"class":476},[470,832,668],{"class":480},[470,834,835],{"class":472,"line":616},[470,836,837],{"class":539},"            # Если каталог то вызываем функцию рекурсивно\n",[470,839,840],{"class":472,"line":636},[470,841,842],{"class":539},"            # Чтобы снова провести обход файлов в подкаталоге как в основном каталоге поиска\n",[470,844,845],{"class":472,"line":648},[470,846,847],{"class":480},"            print_file_names(fullpath)\n",[470,849,850],{"class":472,"line":662},[470,851,520],{"emptyLinePlaceholder":519},[470,853,854,856,859],{"class":472,"line":671},[470,855,688],{"class":480},[470,857,858],{"class":691},"\"pics\"",[470,860,659],{"class":480},[406,862,863],{},"Обратите внимание на этот раз очередь не используется.\nВместо этого алгоритм при обнаружении подкаталога сразу же заходит в него.\nЕстественно что этот второй способ поиска в глубину будет выводить имена файлов в другом порядке, нежели алгоритм с поиском в ширину.\nПоиск в глубину тоже работает с графом и представляет собой алгоритм обхода дерева.\nОтличие от поиска в ширину то что алгоритм поиска в глубину не добавляет подкаталог поиска в очередь, а сразу же заходит в него и ищет в нём файлы.\nПоиск в ширину и поиск в глубину тесно связаны друг с другом. Однако между ними существует важное различие.\nПоиск в глубину не может использоваться для нахождения кратчайшего пути!\nИменно потому что поиск в глубину сразу заходит на максимально возможную глубину по дереву.\nОба алгоритма могут быть использованы для обхода деревьев, но для поиска кратчайшего пути подходит только алгоритм поиска в ширину.\nУ алгоритма поиска в глубину больше применений в топологической сортировке(о ней также было упомянуто в прошлой статье).",[865,866,868],"h5",{"id":867},"определение-дерева","Определение дерева",[406,870,871,872,875],{},"После рассмотрения примера можно привести более точное определение дерева. Дерево представляет собой ",[708,873,874],{},"связанный ациклический граф.","\nРабота алгоритма поиск в глубину идёт исключительно с корневыми деревьями и связанными графами.\nГлавное, что следует помнить — не должно быть циклов в деревьях которые \"обходит\" алгоритм.",[431,877,879],{"id":878},"бинарные-деревья","Бинарные деревья",[406,881,882,883,886],{},"Существует множество разных типов деревьев. Бинарные деревья используются исключительно часто.\nБинарное дерево представляет собой особую разновидность дерева, узлы которого могут иметь не более двух дочерних узлов (отсюда и название бинарные или двоичные деревья).\nДочерние узлы традиционно называют ",[708,884,885],{},"левым и правым узлами",".\nПример бинарного дерева — генеалогическое древо, так как у каждого узла имеются два биологических родителя.\nВ таком дереве между узлами существует чёткая связь — все они составляют одну семью.\nОднако данные могут быть произвольными. Важно то, что ни у одного узла не может быть больше двух дочерних узлов.\nИногда встречаются термины \"левое поддерево\" и \"правое поддерево\".\nДалее рассмотрен пример,в котором используется бинарное дерево.",[410,888,890],{"id":889},"код-хаффмана","Код Хаффмана",[406,892,893,894,900,901,904,905,908,909,911],{},"Код Хаффмана — хороший пример использования бинарных деревьев. Он лежит в основе алгоритмов сжатия текста.\nРазберём как он работает и как в нём применяются деревья.\nПрежде необходимо понять как работает сжатие, и знать, сколько места занимает текстовый файл.\nПредставим файл, содержащий всего одно слово: ",[708,895,896],{},[897,898,899],"strong",{},"dart",". Сколько места он занимает?\nЧтобы узнать это, можно воспользоваться командой ",[897,902,903],{},"stat"," в Unix системах.\nСохраните слово в файле с именем ",[897,906,907],{},"test.txt",", а затем воспользуемся командой ",[897,910,903],{},":",[406,913,914],{},[467,915,916],{},"$ cat test.txt",[406,918,919],{},[467,920,899],{},[406,922,923],{},[467,924,925],{},"$ stat -c %s test.txt",[406,927,928],{},[467,929,930],{},"4",[406,932,933,934,937,938,941,942,945],{},"Итак, файл занимает 4 байта: по 1 байту на символ.\nВыглядит логично. Если предположить, что мы используем кодировку ISO-8859-1. Каждая буква в ней занимает ровно 1 байт.\nНапример, буква ",[708,935,936],{},"t"," в ISO-8859-1 соответствует код 116, который в двоичной системе записывается в виде 01110100, — итого 8 бит.\nКоды ISO-8859-1 содержатся в интервале от 00000000, что соответствует нуль-символу, до 11111111, что соответствует символу ",[708,939,940],{},"ÿ","(латинская буква ",[708,943,944],{},"y"," в нижнем регистре с тремой).\nВсего существует 256 возможных 8-битовых комбинаций из 0 и 1, так что кодировка ISO-8859-1 способна представить до 256 букв.",[702,947,948],{},[406,949,950,953],{},[897,951,952],{},"Кодировки.","\nСуществует множество способов кодирования символов. Можно букву записать в двоичной форме разными способами.\nВсё началось с кодировки ASCII, которая была создана ещё в 1960-х годах в США. ASCII является 7-битной кодировкой.\nК сожалению в неё не вошли многие символы и распространённые обозначения, например, обозначения валют.\nПозже была создана 8 битная кодировка ISO-8859-1, а в дальнейшем выделилось целое семейство ISO-8859.\nВ этой кодировке уже было вдвое больше символов чем в ASCII! Вместо 7 битной из 128 символов стало доступно 256!\nТем не менее этого было недостаточно, и многие страны стали создавать собственные кодировки.\nТак как ISO-8859-1 и ASCII были ориентированы на европейские языки.\nХаос с кодировками при прочтении и отправке текстовых файлов и писем по электронной почте нарастал, пока не появился Юникод!\nЮникод — стандарт кодирования символов который поддерживает символы всех языков.\nЮникод версии 16 по данным на сентябрь 2024 года включает 154 998 символов — большой шаг вперёд по сравнению с 256! Более 1000 это так называемые символы эмодзи.\nВ настоящее время самой популярной кодировкой такого рода считается UTF-8.\nЭта кодировка с переменной длиной кодирования символов; представление одного символа может занимать от 1 до 4 байт(8-32 бит).",[406,955,956],{},"Данный пример я специально упростил назвав кодировку ISO-8859-1 с 8-битным представлением символов, — это удобно за счёт постоянной длины кодирования.\nВыделим основное, что из выше изложенного нужно понимать:",[958,959,960,963],"ul",{},[447,961,962],{},"Алгоритмы сжатия сокращают количество бит, необходимых для представления символов;",[447,964,965],{},"UTF-8 современный стандарт кодирования по умолчанию.",[406,967,968,969,973],{},"Декодируем наше слово ",[708,970,971],{},[897,972,899],{}," в двоичное представление: 01100100 01100001 01110010 01110100.\nМожно воспользоваться таблицей кодировки ISO-8859-1 или преобразователем двоичной записи, чтобы упростить задачу.\nТакже при декодировании мы знаем что одна буква занимает 8 бит, поэтому разделяем последовательность на 8-битные блоки, чтобы её проще было читать.\nДля просмотра двоичного кода текста можно воспользоваться утилитой Unix систем.\nВызываем команду xxd для файла test.txt в котором сохранён текст python(предварительно пакет xxd должен быть установлен в системе).\nВот так это выглядит:",[406,975,976],{},[467,977,978],{},"$ xxd -b test.txt",[406,980,981],{},[467,982,983],{},"00000000: 01100100 01100001 01110010 01110100 dart",[406,985,986,987,989],{},"Далее используется сжатие. Для слова ",[708,988,899],{}," не нужны все 256 возможных букв, достаточно четырёх.\nТаким образом, для представления буквы не требуется 8 бит, можно обойтись двумя.\nМожно определить собственную 2-битную кодировку для этих четырёх букв:",[406,991,992],{},[467,993,994],{},"d = 00",[406,996,997],{},[467,998,999],{},"a = 01",[406,1001,1002],{},[467,1003,1004],{},"r = 10",[406,1006,1007],{},[467,1008,1009],{},"t = 11",[406,1011,1012,1013,1015],{},"В таком случае можно записать слово ",[708,1014,899],{}," в новой нашей кодировке: 00 01 10 11.\nТак работает алгоритм Хаффмана: он ищет все символы в тексте и использует для их представления менее 8 бит.\nВ результате происходит сжатие данных.\nКод Хаффмана генерирует дерево и по этому дереву можно узнать код каждой буквы, начиная с корневого узла.\nКоды букв в кодировке Хаффмана не обязательно должны иметь одинаковую длину.\nЭто важный момент, поэтому рассмотрим ещё один пример.\nПостроим дерево, сгенерированное алгоритмом Хаффмана для фразы \"android paranoid\", будет выглядеть так:",[406,1017,1018],{},[423,1019],{"alt":1020,"src":1021},"Пример дерева по алгоритму Хаффмана","\u002Fimages\u002Fblog\u002Fpython\u002Fst30\u002Fimg_2.png",[406,1023,1024,1025,1027,1028,1031],{},"Здесь мы видим что код для буквы ",[708,1026,406],{}," это 0001. А для буквы ",[708,1029,1030],{},"d"," это уже 10.\nВ данном случае вообще используется три разные длины кодирования символов! Представьте, что вам нужно раскодировать данные: 000101010.\nВ данном случае код может состоять из 2, 3 или 4 цифр! Так как длина кода постоянно может меняться, разбить его на равные фрагменты сразу невозможно.\nЧтобы декодировать, придётся перебирать каждую цифру по отдельности, словно нам их показывают по очереди.\nВот как будем разбирать эту последовательность 000101010 по нашему дереву.",[444,1033,1034,1037,1040,1043,1046],{},[447,1035,1036],{},"Первая цифра ноль, поэтому идём налево;",[447,1038,1039],{},"Вторая цифра снова ноль, снова идём налево;",[447,1041,1042],{},"Третья также ноль, налево;",[447,1044,1045],{},"Четвёртая цифра 1, мы пришли к букве p по нашему дереву.",[447,1047,1048],{},"Остались данные: 01010. Снова начинаем с корневого узла, чтобы найти остальные буквы.",[406,1050,1051,1052,1055,1056,1059,1060,1062,1063,1065],{},"Нашли закодированное слово? Да, это слова ",[708,1053,1054],{},"pad"," (с английского ",[708,1057,1058],{},"блокнот","). Здесь мы видим принципиальное отличие кода Хаффмана от кодировки ISO-8859.\nДлины кодов могут изменяться, поэтому декодирование должно выполняться по-другому.\nУ такой схемы есть своё преимущество. Те буквы которые чаще встречаются в тексте — имеют более короткие коды.\nБуква ",[708,1061,1030],{}," встречается в тексте три раза, а буква ",[708,1064,406],{}," всего один раз.\nВместо того чтобы кодировать все буквы 4 битами, алгоритм применяет повышенное сжатие или сокращение кодов для часто используемых в тексте букв!\nВ длинном тексте это обеспечит большой выйгрыш в памяти!",[406,1067,1068,1069,1072],{},"С кодом Хаффмана нет проблемы \"наложения кодов друг на друга\", потому что буквы помещаются только в листовых узлах.\nИ от корневого узла к каждому листовому существует только один уникальный путь — это одно из уникальных свойств деревьев!\nЭто свойство также гарантирует, что каждой букве будет соответствовать только один код.\nКогда декодируются код по одной цифре, предполагается, что в конечном итоге получается буква.\nЕсли бы в графе присутствовал цикл, то такое предположение не работало бы из-за риска попасть в этот самый цикл.\nНо в дереве циклы заведомо отсутствуют, так что алгоритм гарантированно придёт к какой-нибудь букве.\nА также используется корневое дерево и всегда известно с чего начинать декодирование.\nС другой стороны не каждый граф будет иметь корневой узел.\nНаконец, дерево, используемое в алгоритме называется ",[708,1070,1071],{},"бинарным.","\nУзлы в бинарных деревьях имеют не более двух дочерних узлов — левый и правый, так как в двоичной записи только две цифры 0 и 1.",[702,1074,1075],{},[406,1076,1077,1078,1081],{},"В следующей статье описаны ",[439,1079,1080],{"href":287},"сбалансированные деревья"," и их возможные применения.",[431,1083],{"id":465},[401,1085],{":isList":1086,"title":1087},"[\"Деревья — это разновидность графов, но в деревьях не может быть циклов;\",\"Поиск в глубину — алгоритм обхода графа. Он не подходит для поиска кратчайшего пути(подходит для топологической сортировки).\",\"Бинарное дерево — разновидность дерева, у которого каждый узел может иметь не более двух дочерних узлов;\",\"Unicode является международным стандартом кодирования символов, а кодировка UTF-8 — самая популярная.\"]","ШПАРГАЛКА",[1089,1090,1091],"style",{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}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);}",{"title":465,"searchDepth":490,"depth":523,"links":1093},[1094],{"id":399,"depth":490,"text":282,"children":1095},[1096,1099,1103],{"id":412,"depth":503,"text":413,"children":1097},[1098],{"id":433,"depth":516,"text":434},{"id":718,"depth":503,"text":719,"children":1100},[1101,1102],{"id":867,"depth":523,"text":868},{"id":878,"depth":516,"text":879},{"id":889,"depth":503,"text":890,"children":1104},[1105],{"id":465,"depth":516,"text":465},"2026-02-27","Алгоритмы с деревьями. Алгоритм поиска в глубину(DFS) на деревьях. Алгоритм Хаффмана.","md","images\u002Fblog\u002Fpython\u002Fst30\u002Fimg.png",{},25,30,{"title":282,"description":1107},"pHes4uqZEfPuofzZ7TsLtY_klwTQzbFdbLSu1BWIDQ8",[1116,1118],{"title":274,"path":275,"stem":276,"description":1117,"children":-1},"Алгоритм поиска в ширину на графах для поиска кратчайших путей. Топологическая сортировка.",{"title":286,"path":287,"stem":288,"description":1119,"children":-1},"Бинарное дерево поиска. Сбалансированные деревья. АВЛ-деревья. B-деревья.",1780737510388]