mirror of
https://github.com/krahets/hello-algo.git
synced 2026-05-05 10:13:06 +08:00
170 lines
18 KiB
Markdown
170 lines
18 KiB
Markdown
# Введение в алгоритмы
|
||
|
||
{width="3.8117727471566054in" height="4.595624453193351in"}
|
||
|
||
#### Алгоритмы повсюду
|
||
|
||
> Говоря об алгоритмах, естественно вспомнить о математике. Однако на самом деле многие алгоритмы не связаны со сложной математикой, а больше полага- ются на базовую логику, которая повсеместно встречается в нашей повседнев- ной жизни.
|
||
>
|
||
> Прежде чем углубиться в обсуждение алгоритмов, стоит упомянуть интерес- ный факт: **вы уже точно освоили множество алгоритмов и привыкли при- менять их в повседневной жизни**. Далее приведем несколько конкретных примеров, чтобы подтвердить этот факт.
|
||
>
|
||
> **Пример 1**: **поиск в словаре**. В словаре все слова упорядочены по алфавиту. Предположим, нам нужно найти слово, начинающееся на букву «r». Обычно для этого нужно выполнить следующие действия (см. рис. 1.1):
|
||
|
||
1) открыть словарь примерно на половине страниц и посмотреть, какая буква является первой на этой странице, -- предположим, это буква «m»;
|
||
|
||
2) поскольку в алфавите буква «r» идет после «m», исключаем первую по- ловину словаря, и область поиска сужается до второй половины;
|
||
|
||
3) продолжаем повторять шаги 1 и 2, пока не найдем страницу, где первой буквой слов будет «r».
|
||
|
||

|
||
|
||
> **Рис. 1.1.** Этапы поиска в словаре. Шаг 1
|
||
>
|
||
> 
|
||
|
||

|
||
|
||
> **Рис. 1.1.** *Продолжение*. Шаги 2--3
|
||
>
|
||
> 
|
||
|
||

|
||
|
||
> **Рис. 1.1.** *Окончание*. Шаги 4--5
|
||
>
|
||
> Навык поиска в словаре, которым владеет каждый школьник, на самом деле является известным алгоритмом двоичного поиска. С точки зрения структуры данных словарь можно рассматривать как отсортированный массив. С точки зрения алгоритма последовательность операций по поиску в словаре можно считать двоичным поиском.
|
||
>
|
||
> **Пример 2**: **упорядочивание карт**. Во время игры в карты необходимо каж- дый раз упорядочивать карты в руке от меньшего к большему. Для этого нужно выполнить следующие действия (см. рис. 1.2):
|
||
|
||
1) разделить карты на упорядоченную и неупорядоченную части, предпо- лагая, что изначально самая левая карта уже упорядочена;
|
||
|
||
2) из неупорядоченной части извлечь одну карту и вставить ее в правиль- ное место в упорядоченной части. После этого две самые левые карты станут упорядоченными;
|
||
|
||
3) повторять шаг 2, каждый раз перемещая одну карту из неупорядоченной части в упорядоченную, пока все карты не станут упорядоченными.
|
||
|
||
> **Рис. 1.2.** Этапы упорядочивания карт
|
||
>
|
||
> Метод упорядочивания карт по своей сути является алгоритмом сортиров- ки вставками, который весьма эффективен при обработке небольших наборов данных. Многие функции сортировки в библиотеках программирования ис- пользуют именно этот алгоритм.
|
||
>
|
||
> **Пример 3**: **сдача**. Предположим, что в супермаркете мы купили товар стои- мостью 69 руб. и дали кассиру купюру в 100 руб. Кассир должен вернуть нам 31 руб. Для этого ему нужно выполнить действия, показанные на рис. 1.3.
|
||
|
||
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.3.** Этапы выдачи сдачи
|
||
>
|
||
> В этих шагах мы на каждом этапе выбираем наилучший вариант (используя купюры наибольшего номинала), в итоге получая оптимальную схему сдачи. С точки зрения структуры данных и алгоритмов этот метод по своей сути яв- ляется жадным алгоритмом.
|
||
>
|
||
> От приготовления блюда до межзвездных путешествий − решение практи- чески любой задачи неразрывно связано с алгоритмами. Появление компью- теров позволило нам с помощью программирования хранить структуры дан- ных в памяти, а также писать код для вызовов к центральному и графическому процессору для выполнения алгоритмов. Таким образом, мы можем перено- сить задачи из реальной жизни в компьютер, решая различные сложные про- блемы более эффективно.
|
||
|
||
#### что такое алгоритм
|
||
|
||
1. **Определение алгоритма**
|
||
|
||
> *Алгоритм* -- это набор инструкций или шагов, предназначенных для решения конкретной задачи за ограниченное время, обладающий следующими свой- ствами:
|
||
|
||
1) задача четко определена, включает ясные определения входных и вы- ходных данных;
|
||
|
||
2) обладает осуществимостью, может быть выполнен за ограниченное ко- личество шагов, времени и памяти;
|
||
|
||
3) каждый шаг имеет определенное значение, при одинаковых входных данных и условиях выполнения результат всегда будет одинаковым.
|
||
|
||
### Определение структуры данных
|
||
|
||
> *Структура данных* -- это способ организации и хранения данных, включающий содержимое данных, их взаимосвязи и методы операций с ними. Структура данных преследует следующие цели:
|
||
|
||
1) минимизацию занимаемого пространства для экономии памяти ком- пьютера;
|
||
|
||
2) максимально быструю обработку данных, включая доступ, добавление, удаление и обновление данных;
|
||
|
||
3) обеспечение простого представления данных и логической информации для эффективного выполнения алгоритмов.
|
||
|
||
> **Проектирование структуры данных** -- **это процесс, полный компромис- сов**. Если вы хотите улучшить один аспект, часто приходится идти на уступки в другом. Приведем два примера.
|
||
|
||
1. Связный список, по сравнению с массивом, более удобен для добавления и удаления данных, но имеет проблемы со скоростью доступа к данным.
|
||
|
||
2. Граф, по сравнению со связным списком, предоставляет более богатую логическую информацию, но требует большего объема памяти.
|
||
|
||
### Взаимосвязь структур данных и алгоритмов
|
||
|
||
> Структуры данных и алгоритмы тесно взаимосвязаны, что проявляется в сле- дующих трех аспектах (см. рис. 1.4):
|
||
|
||
1) структуры данных являются основой алгоритмов. Они обеспечивают структурированное хранение данных и методы их обработки;
|
||
|
||
2) алгоритмы оживляют структуры данных. Сами по себе структуры дан- ных лишь хранят информацию, но в сочетании с алгоритмами они по- зволяют решать конкретные задачи;
|
||
|
||
3) алгоритмы можно реализовать на основе различных структур данных, однако эффективность их выполнения может значительно различаться. Поэтому выбор подходящей структуры данных является ключевым факто- ром.
|
||
|
||
<!-- -->
|
||
|
||
2. Что такое алгоритм ❖ **31**
|
||
|
||

|
||
|
||
> **Рис. 1.4.** Взаимосвязь структур данных и алгоритмов
|
||
>
|
||
> Структуры данных и алгоритмы подобны конструктору, как показано на рис. 1.5. Комплект конструктора, помимо множества деталей, содержит так- же подробную инструкцию по сборке. Следуя этой инструкции шаг за шагом, можно собрать красивую модель.
|
||
|
||
{width="5.09092738407699in" height="3.15in"}
|
||
|
||
> **Рис. 1.5.** Сборка конструктора
|
||
>
|
||
> Подробное описание аналогии с конструктором представлено в табл. 1.1.
|
||
>
|
||
> **Таблица 1.1.** Сравнение структур данных и алгоритмов с конструктором
|
||
>
|
||
> **Структуры данных и алгоритмы Конструктор**
|
||
>
|
||
> Входные данные Несобранные детали конструктора
|
||
>
|
||
> Структура данных Организация деталей конструктора, включая фор- му, размер, способы соединения и т. д.
|
||
>
|
||
> Алгоритм Последовательность действий по сборке деталей в целевую модель
|
||
>
|
||
> Выходные данные Собранная модель конструктора
|
||
>
|
||
> Стоит отметить, что структуры данных и алгоритмы не зависят от языка программирования. Именно поэтому данная книга предлагает их реализации на различных языках.
|
||
|
||
#### резюме
|
||
|
||
- Алгоритмы повсеместно присутствуют в нашей повседневной жизни и не являются недосягаемыми сложными знаниями. На самом деле мы уже освоили множество алгоритмов, которые помогают решать различ- ные жизненные задачи.
|
||
|
||
- Принцип поиска в словаре соответствует алгоритму двоичного поис- ка. Бинарный поиск иллюстрирует важную идею алгоритмов «разделяй и властвуй».
|
||
|
||
- Процесс сортировки карт в колоде очень похож на алгоритм сортировки вставками, который хорошо подходит для сортировки небольших набо- ров данных.
|
||
|
||
- Процесс размена валюты по своей сути является жадным алгоритмом, в котором на каждом этапе принимается наилучшее на данный момент решение.
|
||
|
||
- Алгоритм представляет собой набор инструкций или шагов, предназна- ченных для решения конкретной задачи в ограниченное время, а струк- тура данных -- это способ организации и хранения данных в компьютере.
|
||
|
||
- Структуры данных и алгоритмы тесно связаны. Структуры данных явля- ются основой для алгоритмов, а алгоритмы оживляют структуры данных.
|
||
|
||
- Структуры данных и алгоритмы можно сравнить с конструктором: де- тали конструктора представляют данные, их форма и способы соедине- ния -- структуры данных, а этапы сборки конструктора соответствуют алгоритмам.
|
||
|
||
### Вопросы и ответы
|
||
|
||
> 1.3. Резюме ❖ **33**
|
||
>
|
||
> **Вопрос**. Я программист, и я никогда не использовал алгоритмы для решения задач в своей повседневной работе, поскольку часто используемые алгорит- мы уже встроены в языки программирования и их можно использовать на- прямую. Означает ли это, что задачи, с которыми мы сталкиваемся на работе, не требуют применения алгоритмов?
|
||
>
|
||
> **Ответ**. Если сравнить конкретные профессиональные навыки с приемами в боевых искусствах, то базовые дисциплины скорее напоминают «внутрен- нюю силу».
|
||
>
|
||
> Я считаю, что изучение алгоритмов (и других базовых дисциплин) важно не для того, чтобы реализовывать их с нуля в работе, а для того, чтобы на осно- ве полученных знаний принимать профессиональные решения и оценки при решении задач, тем самым повышая общее качество работы. Простой пример: каждый язык программирования имеет встроенные функции сортировки.
|
||
>
|
||
> Если бы мы не изучали структуры данных и алгоритмы, то, получив любые данные, мы, возможно, просто передали бы их этой функции сортировки. Все работает гладко, производительность хорошая, и на первый взгляд проблем нет. Однако если мы изучили алгоритмы, то знаем, что временная сложность встроенной функции сортировки составляет *O*(*n* log *n*). Если же данные пред- ставлены целыми числами фиксированной разрядности (например, номерами студентов), то можно использовать более эффективный метод поразрядной сортировки, снизив временную сложность до *O*(*nk*), где *k* -- это количество раз- рядов. При больших объемах данных экономия времени выполнения может привести к значительным преимуществам, таким как снижение затрат и улуч-
|
||
>
|
||
> шение пользовательского опыта.
|
||
>
|
||
> В инженерной практике множество задач трудно решить оптимальным об- разом, и многие из них решаются «как-то». Сложность задачи зависит как от ее природы, так и от уровня знаний и опыта человека, который ее анализирует. Чем более полными знаниями и большим опытом обладает человек, тем глубже он может проанализировать проблему и тем изящнее может быть ее решение.
|
||
>
|
||
> Глава 2
|