This commit is contained in:
krahets
2026-04-03 18:46:15 +08:00
parent 377736b1bd
commit 9d21ca86b0
352 changed files with 46563 additions and 11262 deletions
@@ -4,63 +4,63 @@ comments: true
# 1.1   Алгоритмы повсюду
Когда мы слышим слово "алгоритм", мы естественным образом думаем о математике. Однако на деле многие алгоритмы не связаны со сложной математикой, а в гораздо большей степени опираются на базовую логику, которую можно увидеть повсюду в повседневной жизни.
Говоря об алгоритмах, естественно вспомнить о математике. Однако на самом деле многие алгоритмы не связаны со сложной математикой, а больше полагаются на базовую логику, которая повсеместно встречается в нашей повседневной жизни.
Прежде чем официально перейти к разговору об алгоритмах, стоит поделиться одним любопытным фактом: **ты уже незаметно для себя освоил множество алгоритмов и привык применять их в повседневной жизни**. Ниже я приведу несколько конкретных примеров, чтобы это показать.
Прежде чем углубиться в обсуждение алгоритмов, стоит упомянуть интересный факт: **вы уже точно освоили множество алгоритмов и привыкли применять их в повседневной жизни**. Далее приведем несколько конкретных примеров, чтобы подтвердить этот факт.
**Пример 1: поиск в словаре**. В английском словаре слова расположены в алфавитном порядке. Предположим, нам нужно найти слово, начинающееся на букву $r$; обычно это делается так, как показано ниже.
**Пример 1: поиск в словаре**. В словаре все слова упорядочены по алфавиту. Предположим, нам нужно найти слово, начинающееся на букву $r$; обычно для этого нужно выполнить следующие действия.
1. Открой словарь примерно посередине и посмотри, с какой буквы начинается страница; предположим, это буква $m$.
2. Поскольку в алфавите $r$ идет после $m$, первую половину словаря можно отбросить, и область поиска сузится до второй половины.
3. Повторяй шаги `1.` и `2.` до тех пор, пока не найдешь страницу, на которой слово начинается с буквы $r$.
1. Откройте словарь примерно на половине страниц и посмотрите, какая буква является первой на этой странице; предположим, это буква $m$.
2. Поскольку в алфавите буква $r$ идет после $m$, исключаем первую половину словаря, и область поиска сужается до второй половины.
3. Продолжайте повторять шаги `1.` и `2.` , пока не найдете страницу, где первой буквой слов будет $r$.
=== "<1>"
![Процесс поиска в словаре](algorithms_are_everywhere.assets/binary_search_dictionary_step1.png){ class="animation-figure" }
![Этапы поиска в словаре. Шаг 1](algorithms_are_everywhere.assets/binary_search_dictionary_step1.png){ class="animation-figure" }
=== "<2>"
![Бинарный поиск в словаре, шаг 2](algorithms_are_everywhere.assets/binary_search_dictionary_step2.png){ class="animation-figure" }
![Этапы поиска в словаре. Шаг 2](algorithms_are_everywhere.assets/binary_search_dictionary_step2.png){ class="animation-figure" }
=== "<3>"
![Бинарный поиск в словаре, шаг 3](algorithms_are_everywhere.assets/binary_search_dictionary_step3.png){ class="animation-figure" }
![Этапы поиска в словаре. Шаг 3](algorithms_are_everywhere.assets/binary_search_dictionary_step3.png){ class="animation-figure" }
=== "<4>"
![Бинарный поиск в словаре, шаг 4](algorithms_are_everywhere.assets/binary_search_dictionary_step4.png){ class="animation-figure" }
![Этапы поиска в словаре. Шаг 4](algorithms_are_everywhere.assets/binary_search_dictionary_step4.png){ class="animation-figure" }
=== "<5>"
![Бинарный поиск в словаре, шаг 5](algorithms_are_everywhere.assets/binary_search_dictionary_step5.png){ class="animation-figure" }
![Этапы поиска в словаре. Шаг 5](algorithms_are_everywhere.assets/binary_search_dictionary_step5.png){ class="animation-figure" }
<p align="center"> Рисунок 1-1 &nbsp; Процесс поиска в словаре </p>
<p align="center"> Рисунок 1-1 &nbsp; Этапы поиска в словаре. Шаг 1 </p>
Поиск в словаре, обязательный навык для школьников, на самом деле и есть знаменитый алгоритм "двоичного поиска". С точки зрения структур данных словарь можно рассматривать как отсортированный "массив"; с точки зрения алгоритмов последовательность действий при поиске слова в словаре можно считать алгоритмом "двоичного поиска".
Навык поиска в словаре, которым владеет каждый школьник, на самом деле является известным алгоритмом двоичного поиска. С точки зрения структуры данных словарь можно рассматривать как отсортированный массив; с точки зрения алгоритма последовательность операций по поиску в словаре можно считать двоичным поиском.
**Пример 2: упорядочивание карт**. Во время игры в карты нам нужно раскладывать карты в руке по возрастанию; процесс выглядит так, как показано ниже.
**Пример 2: упорядочивание карт**. Во время игры в карты необходимо каждый раз упорядочивать карты в руке от меньшего к большему. Для этого нужно выполнить следующие действия.
1. Раздели карты на "упорядоченную" и "неупорядоченную" части и предположи, что в начальный момент самая левая карта уже стоит на правильном месте.
2. Возьми одну карту из неупорядоченной части и вставь ее в правильную позицию внутри упорядоченной части; после этого две самые левые карты уже будут упорядочены.
3. Повторяй шаг `2.` , каждый раз перенося одну карту из неупорядоченной части в упорядоченную, пока все карты не окажутся в порядке.
1. Разделите карты на упорядоченную и неупорядоченную части, предполагая, что изначально самая левая карта уже упорядочена.
2. Из неупорядоченной части извлеките одну карту и вставьте ее в правильное место в упорядоченной части; после этого две самые левые карты станут упорядоченными.
3. Повторяйте шаг `2.` , каждый раз перемещая одну карту из неупорядоченной части в упорядоченную, пока все карты не станут упорядоченными.
![Процесс сортировки колоды карт](algorithms_are_everywhere.assets/playing_cards_sorting.png){ class="animation-figure" }
![Этапы упорядочивания карт](algorithms_are_everywhere.assets/playing_cards_sorting.png){ class="animation-figure" }
<p align="center"> Рисунок 1-2 &nbsp; Процесс сортировки колоды карт </p>
<p align="center"> Рисунок 1-2 &nbsp; Этапы упорядочивания карт </p>
Описанный выше способ раскладывать карты по сути является алгоритмом "сортировки вставками", который очень эффективен на небольших наборах данных. Во многих языках программирования во встроенных функциях сортировки тоже можно увидеть этот алгоритм.
Метод упорядочивания карт по своей сути является алгоритмом сортировки вставками, который весьма эффективен при обработке небольших наборов данных. Многие функции сортировки в библиотеках программирования используют именно этот алгоритм.
**Пример 3: выдача сдачи**. Предположим, в супермаркете мы купили товар на $69$ и дали кассиру $100$, поэтому он должен вернуть нам $31$ сдачи. Этот процесс можно наглядно представить так, как показано на рисунке 1-3.
**Пример 3: сдача**. Предположим, что в супермаркете мы купили товар стоимостью $69$ руб. и дали кассиру купюру в $100$ руб. Кассир должен вернуть нам $31$ руб. Для этого ему нужно выполнить следующие действия.
1. Доступные варианты - это купюры достоинством меньше $31$, например $1$, $5$, $10$ и $20$.
2. Возьми самую большую купюру из доступных, то есть $20$, тогда останется $31 - 20 = 11$.
3. Возьми самую большую купюру из оставшихся, то есть $10$, тогда останется $11 - 10 = 1$.
4. Возьми самую большую купюру из оставшихся, то есть $1$, тогда останется $1 - 1 = 0$.
5. Выдача сдачи завершена, итоговая комбинация: $20 + 10 + 1 = 31$.
1. Варианты выбора - это купюры номиналом меньше $31$ руб. Пусть у нас имеются номиналы $1$ , $5$ , $10$ и $20$ руб.
2. Возьмем самую крупную доступную купюру в $20$ руб. Остаток сдачи составит $31 - 20 = 11$ руб.
3. Возьмем самую крупную из оставшихся купюр в $10$ руб. Остаток составит $11 - 10 = 1$ руб.
4. Возьмем самую крупную из оставшихся купюр в $1$ руб. Остаток составит $1 - 1 = 0$ руб.
5. Завершим выдачу сдачи, схема: $20 + 10 + 1 = 31$ руб.
![Процесс выдачи сдачи](algorithms_are_everywhere.assets/greedy_change.png){ class="animation-figure" }
![Этапы выдачи сдачи](algorithms_are_everywhere.assets/greedy_change.png){ class="animation-figure" }
<p align="center"> Рисунок 1-3 &nbsp; Процесс выдачи сдачи </p>
<p align="center"> Рисунок 1-3 &nbsp; Этапы выдачи сдачи </p>
В описанных шагах на каждом этапе выбирается наилучший вариант из доступных в текущий момент, то есть используется купюра наибольшего номинала; в результате получается рабочая схема выдачи сдачи. С точки зрения структур данных и алгоритмов такой подход называется "жадным" алгоритмом.
В этих шагах мы на каждом этапе выбираем наилучший вариант, используя купюры наибольшего номинала, и в итоге получаем рабочую схему сдачи. С точки зрения структуры данных и алгоритмов этот метод по своей сути является жадным алгоритмом.
От приготовления еды до межзвездных путешествий почти любое решение задачи связано с алгоритмами. Появление компьютеров позволило нам хранить структуры данных в памяти и писать код, который вызывает CPU и GPU для выполнения алгоритмов. Благодаря этому мы можем переносить реальные задачи в компьютер и решать самые разные сложные проблемы более эффективно.
От приготовления блюда до межзвездных путешествий решение практически любой задачи неразрывно связано с алгоритмами. Появление компьютеров позволило нам с помощью программирования хранить структуры данных в памяти, а также писать код для вызовов к CPU и GPU для выполнения алгоритмов. Таким образом, мы можем переносить задачи из реальной жизни в компьютер и решать различные сложные проблемы более эффективно.
!!! tip
Если ты все еще смутно представляешь себе такие понятия, как структуры данных, алгоритмы, массивы и двоичный поиск, просто продолжай читать. Эта книга постепенно введет тебя в мир понимания структур данных и алгоритмов.
Если представление о структурах данных, алгоритмах, массивах и двоичном поиске пока остается расплывчатым, просто продолжайте читать. Эта книга постепенно введет вас в мир структур данных и алгоритмов.
+3 -3
View File
@@ -9,12 +9,12 @@ icon: material/calculator-variant-outline
!!! abstract
Юная девушка легко кружится в танце среди данных, а подол ее платья струится мелодией алгоритмов.
Юная девушка кружится в танце, переплетаясь с данными, а по подолу ее платья струится мелодия алгоритмов.
Она приглашает тебя присоединиться к танцу: следуй за ее шагами и войди в мир алгоритмов, полный логики и красоты.
Она приглашает вас присоединиться к танцу: следуйте за ее шагами и войдите в мир алгоритмов, полный логики и красоты.
## Содержание главы
- [1.1 &nbsp; Алгоритмы повсюду](algorithms_are_everywhere.md)
- [1.2 &nbsp; Что такое структуры данных и алгоритмы](what_is_dsa.md)
- [1.2 &nbsp; Что такое алгоритм](what_is_dsa.md)
- [1.3 &nbsp; Резюме](summary.md)
+13 -13
View File
@@ -6,23 +6,23 @@ comments: true
### 1. &nbsp; Ключевые выводы
- Алгоритмы повсюду встречаются в повседневной жизни и вовсе не являются чем-то далеким и эзотерическим. На деле мы уже давно незаметно для себя освоили множество алгоритмов и используем их для решения самых разных жизненных задач.
- Принцип поиска в словаре соответствует алгоритму двоичного поиска. Двоичный поиск воплощает важную алгоритмическую идею "разделяй и властвуй".
- Процесс раскладывания карт очень похож на алгоритм сортировки вставками. Сортировка вставками подходит для упорядочивания небольших наборов данных.
- Выдача сдачи по шагам по своей сути является жадным алгоритмом, в котором на каждом этапе выбирается лучшее решение в текущей ситуации.
- Алгоритм - это набор инструкций или шагов, который решает конкретную задачу за конечное время, а структура данных - это способ, которым компьютер организует и хранит данные.
- Структуры данных и алгоритмы тесно связаны. Структуры данных являются основой алгоритмов, а алгоритмы оживляют структуры данных.
- Структуры данных и алгоритмы можно сравнить со сборкой конструктора: детали представляют данные, форма деталей и способ их соединения представляют структуру данных, а шаги сборки соответствуют алгоритму.
- Алгоритмы повсеместно присутствуют в нашей повседневной жизни и не являются недосягаемыми сложными знаниями. На самом деле мы уже освоили множество алгоритмов, которые помогают решать различные жизненные задачи.
- Принцип поиска в словаре соответствует алгоритму двоичного поиска. Двоичный поиск иллюстрирует важную идею алгоритмов "разделяй и властвуй".
- Процесс сортировки карт в колоде очень похож на алгоритм сортировки вставками, который хорошо подходит для сортировки небольших наборов данных.
- Процесс размена по своей сути является жадным алгоритмом, в котором на каждом этапе принимается наилучшее на данный момент решение.
- Алгоритм представляет собой набор инструкций или шагов, предназначенных для решения конкретной задачи в ограниченное время, а структура данных - это способ организации и хранения данных в компьютере.
- Структуры данных и алгоритмы тесно связаны. Структуры данных являются основой для алгоритмов, а алгоритмы оживляют структуры данных.
- Структуры данных и алгоритмы можно сравнить с конструктором: детали конструктора представляют данные, их форма и способы соединения - структуры данных, а этапы сборки конструктора соответствуют алгоритмам.
### 2. &nbsp; Q & A
**Q**: Я программист и в повседневной работе никогда не решал задачи "алгоритмами": распространенные алгоритмы уже инкапсулированы в языках программирования, и ими можно пользоваться напрямую. Значит ли это, что рабочие задачи еще не дошли до уровня, где действительно нужны алгоритмы?
**Q**: Я программист и в повседневной работе никогда не использовал алгоритмы для решения задач, поскольку часто используемые алгоритмы уже встроены в языки программирования и ими можно пользоваться напрямую. Значит ли это, что рабочие задачи еще не требуют применения алгоритмов?
Если сравнить конкретные рабочие навыки с "приемами" в боевых искусствах, то фундаментальные дисциплины скорее напоминают "внутреннюю силу".
Если сравнить конкретные профессиональные навыки с приемами в боевых искусствах, то базовые дисциплины скорее напоминают "внутреннюю силу".
Я считаю, что смысл изучения алгоритмов (и других фундаментальных дисциплин) не в том, чтобы каждый раз реализовывать их с нуля в работе, а в том, чтобы, опираясь на полученные знания, уметь профессионально реагировать и принимать решения при решении задач, тем самым повышая общее качество работы. Вот простой пример: в каждом языке программирования есть встроенная функция сортировки.
Я считаю, что изучение алгоритмов и других базовых дисциплин важно не для того, чтобы реализовывать их с нуля в работе, а для того, чтобы на основе полученных знаний принимать профессиональные решения и оценки при решении задач, тем самым повышая общее качество работы. Простой пример: каждый язык программирования имеет встроенные функции сортировки.
- Если мы не изучали структуры данных и алгоритмы, то для любых данных, скорее всего, просто отдали бы их этой функции сортировки. Все работает гладко, производительность хорошая, и на первый взгляд никаких проблем нет.
- Но если мы изучали алгоритмы, то знаем, что временная сложность встроенной сортировки равна $O(n \log n)$ ; однако если данные состоят из целых чисел фиксированной разрядности (например, номеров студентов), можно воспользоваться более эффективной "поразрядной сортировкой", снизив сложность до $O(nk)$ , где $k$ - число разрядов. Когда объем данных очень велик, сэкономленное время выполнения может принести заметную пользу, например снизить издержки и улучшить пользовательский опыт.
- Если бы мы не изучали структуры данных и алгоритмы, то, получив любые данные, возможно, просто передали бы их этой функции сортировки. Все работает гладко, производительность хорошая, и на первый взгляд проблем нет.
- Однако если мы изучили алгоритмы, то знаем, что временная сложность встроенной функции сортировки составляет $O(n \log n)$ ; если же данные представлены целыми числами фиксированной разрядности, например номерами студентов, то можно использовать более эффективный метод поразрядной сортировки, снизив временную сложность до $O(nk)$ , где $k$ - это количество разрядов, а при больших объемах данных выиграть во времени, затратах и пользовательском опыте.
В инженерной практике огромное количество задач трудно довести до оптимального решения, и многие из них решаются лишь "примерно". Сложность задачи зависит, с одной стороны, от ее собственной природы, а с другой - от запаса знаний человека, который на нее смотрит. Чем полнее знания и чем больше опыт, тем глубже получается анализ задачи и тем изящнее ее можно решить.
В инженерной практике множество задач трудно решить оптимальным образом, и многие из них решаются "как-то". Сложность задачи зависит как от ее природы, так и от уровня знаний и опыта человека, который ее анализирует. Чем более полными знаниями и большим опытом обладает человек, тем глубже он может проанализировать проблему и тем изящнее может быть ее решение.
+26 -26
View File
@@ -6,60 +6,60 @@ comments: true
## 1.2.1 &nbsp; Определение алгоритма
<u>Алгоритм (algorithm)</u> - это набор инструкций или шагов, который решает конкретную задачу за конечное время. Он обладает следующими свойствами.
<u>Алгоритм (algorithm)</u> - это набор инструкций или шагов, предназначенных для решения конкретной задачи за ограниченное время. Он обладает следующими свойствами.
- Задача четко определена и имеет ясные определения входных и выходных данных.
- Алгоритм осуществим и может быть выполнен за конечное число шагов, времени и памяти.
- Каждый шаг имеет однозначный смысл, и при одинаковых входных данных и условиях выполнения результат всегда будет одинаковым.
- Задача четко определена и включает ясные определения входных и выходных данных.
- Обладает осуществимостью и может быть выполнен за ограниченное количество шагов, времени и памяти.
- Каждый шаг имеет определенное значение, и при одинаковых входных данных и условиях выполнения результат всегда будет одинаковым.
## 1.2.2 &nbsp; Определение структуры данных
<u>Структура данных (data structure)</u> - это способ организации и хранения данных, охватывающий само содержимое данных, связи между данными и методы работы с ними. У нее есть следующие цели проектирования.
<u>Структура данных (data structure)</u> - это способ организации и хранения данных, включающий содержимое данных, их взаимосвязи и методы операций с ними. Структура данных преследует следующие цели.
- Занимать как можно меньше места, чтобы экономить память компьютера.
- Выполнять операции над данными как можно быстрее, включая доступ, добавление, удаление, обновление и т. д.
- Предоставлять компактное представление данных и логическую информацию, чтобы алгоритмы могли работать эффективно.
- Минимизировать занимаемое пространство для экономии памяти компьютера.
- Обеспечивать максимально быструю обработку данных, включая доступ, добавление, удаление и обновление данных.
- Обеспечивать простое представление данных и логическую информацию для эффективного выполнения алгоритмов.
**Проектирование структур данных - это процесс, полный компромиссов**. Если мы хотим улучшить что-то одно, то часто вынуждены уступить в чем-то другом. Ниже приведены два примера.
**Проектирование структуры данных - это процесс, полный компромиссов**. Если вы хотите улучшить один аспект, часто приходится идти на уступки в другом. Приведем два примера.
- По сравнению с массивами связные списки удобнее для добавления и удаления данных, но жертвуют скоростью доступа к ним.
- По сравнению со связными списками графы предоставляют более богатую логическую информацию, но требуют большего объема памяти.
- Связный список, по сравнению с массивом, более удобен для добавления и удаления данных, но имеет проблемы со скоростью доступа к данным.
- Граф, по сравнению со связным списком, предоставляет более богатую логическую информацию, но требует большего объема памяти.
## 1.2.3 &nbsp; Связь между структурами данных и алгоритмами
Как показано на рисунке 1-4, структуры данных и алгоритмы тесно связаны и сильно зависят друг от друга; это проявляется в следующих трех аспектах.
Как показано на рисунке 1-4, структуры данных и алгоритмы тесно взаимосвязаны, что проявляется в следующих трех аспектах.
- Структуры данных служат фундаментом алгоритмов. Они дают алгоритмам структурированный способ хранения данных и методы работы с ними.
- Алгоритмы оживляют структуры данных. Сами по себе структуры данных лишь хранят информацию, а в сочетании с алгоритмами позволяют решать конкретные задачи.
- Алгоритмы обычно можно реализовать на основе разных структур данных, но эффективность выполнения может сильно различаться, поэтому выбор подходящей структуры данных является ключевым.
- Структуры данных являются основой алгоритмов. Они обеспечивают структурированное хранение данных и методы их обработки.
- Алгоритмы оживляют структуры данных. Сами по себе структуры данных лишь хранят информацию, но в сочетании с алгоритмами они позволяют решать конкретные задачи.
- Алгоритмы можно реализовать на основе различных структур данных, однако эффективность их выполнения может значительно различаться, поэтому выбор подходящей структуры данных является ключевым фактором.
![Связь между структурами данных и алгоритмами](what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png){ class="animation-figure" }
<p align="center"> Рисунок 1-4 &nbsp; Связь между структурами данных и алгоритмами </p>
Структуры данных и алгоритмы похожи на сборку конструктора, показанную на рисунке 1-5. В набор конструктора, помимо множества деталей, входит и подробная инструкция по сборке. Если шаг за шагом следовать этой инструкции, можно собрать красивую модель.
Структуры данных и алгоритмы подобны конструктору, как показано на рисунке 1-5. Комплект конструктора, помимо множества деталей, содержит также подробную инструкцию по сборке. Следуя этой инструкции шаг за шагом, можно собрать красивую модель.
![Сборка конструктора](what_is_dsa.assets/assembling_blocks.png){ class="animation-figure" }
<p align="center"> Рисунок 1-5 &nbsp; Сборка конструктора </p>
Подробное соответствие между ними показано в таблице 1-1.
Подробное описание аналогии с конструктором представлено в таблице 1-1.
<p align="center"> Таблица 1-1 &nbsp; Сравнение структур данных и алгоритмов со сборкой конструктора </p>
<p align="center"> Таблица 1-1 &nbsp; Сравнение структур данных и алгоритмов с конструктором </p>
<div class="center-table" markdown>
| Структуры данных и алгоритмы | Сборка конструктора |
| ---------------------------- | ------------------------------------------ |
| Входные данные | Несобранные детали конструктора |
| Структура данных | Организация деталей: форма, размер, способ соединения и т. д. |
| Алгоритм | Последовательность шагов по сборке деталей в целевую форму |
| Выходные данные | Собранная модель конструктора |
| Структуры данных и алгоритмы | Конструктор |
| ---------------------------- | ----------- |
| Входные данные | Несобранные детали конструктора |
| Структура данных | Организация деталей конструктора, включая форму, размер, способы соединения и т. д. |
| Алгоритм | Последовательность действий по сборке деталей в целевую модель |
| Выходные данные | Собранная модель конструктора |
</div>
Стоит отметить, что структуры данных и алгоритмы не зависят от конкретного языка программирования. Именно поэтому эта книга может давать реализации на разных языках программирования.
Стоит отметить, что структуры данных и алгоритмы не зависят от языка программирования. Именно поэтому данная книга предлагает их реализации на различных языках.
!!! tip "Принятое сокращение"
В реальных обсуждениях мы обычно сокращаем выражение "структуры данных и алгоритмы" до просто "алгоритмы". Например, хорошо известные алгоритмические задачи LeetCode на деле одновременно проверяют знания и по структурам данных, и по алгоритмам.
В реальных обсуждениях выражение "структуры данных и алгоритмы" обычно сокращают до просто "алгоритмы". Например, хорошо известные задачи LeetCode на деле одновременно проверяют знания и по структурам данных, и по алгоритмам.