fix(guide): simplify directory structure

This commit is contained in:
Mrugesh Mohapatra
2018-10-16 21:26:13 +05:30
parent f989c28c52
commit da0df12ab7
35752 changed files with 0 additions and 317652 deletions

View File

@@ -0,0 +1,31 @@
---
title: Behavioral patterns
localeTitle: Поведенческие модели
---
## Поведенческие модели
Поведенческие шаблоны проектирования - это шаблоны проектирования, которые идентифицируют общие проблемы связи между объектами и реализуют эти шаблоны. Таким образом, эти шаблоны увеличивают гибкость при выполнении этого сообщения, делая программное обеспечение более надежным и легким в обслуживании.
Примеры такого типа дизайна включают:
1. **Схема цепочки ответственности** : объекты команд обрабатываются или передаются другим объектам с помощью объектов, содержащих логические объекты.
2. **Шаблон команды** : объекты команды инкапсулируют действие и его параметры.
3. **Шаблон интерпретатора** . Внедрите специализированный компьютерный язык для быстрого решения определенного набора проблем.
4. **Итератор** : Итераторы используются для доступа к элементам агрегатного объекта последовательно, не подвергая его базовому представлению.
5. **Схема посредника** : обеспечивает унифицированный интерфейс для набора интерфейсов в подсистеме.
6. **Memento pattern** : обеспечивает возможность восстановления объекта до его предыдущего состояния (откат).
7. **Шаблон Null Object** : Предназначен для использования в качестве значения по умолчанию для объекта.
8. **Шаблон наблюдателя** : aka P **ublish / Подписка** или **прослушиватель** **событий** . Объекты регистрируются, чтобы наблюдать событие, которое может быть поднято другим объектом.
9. **Слабая контрольная модель** : Отмените наблюдателя от наблюдаемого.
10. **Стек протокола** : связь обрабатывается несколькими уровнями, которые образуют иерархию инкапсуляции.
11. **Шаблон запланированной задачи** : задание планируется выполнить с определенным интервалом или временем синхронизации (используется в вычислениях в реальном времени).
12. **Однопользовательский шаблон посетителя** : оптимизируйте реализацию посетителя, который выделен, используется только один раз, а затем удаляется.
13. **Спецификация** : рекомбинируемая бизнес-логика логическим способом.
14. **Шаблон состояния** : чистый способ для объекта частично изменить свой тип во время выполнения.
15. **Стратегия** : алгоритмы могут выбираться «на лету».
16. **Шаблон метода шаблона** : Описывает программный скелет программы.
17. **Шаблон посетителя** : способ отделить алгоритм от объекта.
### источники
[https://en.wikipedia.org/wiki/Behavioral\_pattern](https://en.wikipedia.org/wiki/Behavioral_pattern)

View File

@@ -0,0 +1,21 @@
---
title: Creational patterns
localeTitle: Создание шаблонов
---
## Создание шаблонов
Творческие шаблоны проектирования - это шаблоны проектирования, которые касаются механизмов создания объектов, пытаясь создать объекты в соответствии с ситуацией. Основная форма создания объекта может привести к проблемам проектирования или сложности с дизайном. Создание шаблонов проектирования решает эту проблему, как-то контролируя создание этого объекта.
Творческие шаблоны проектирования состоят из двух доминирующих идей. Одним из них является инкапсуляция знаний о том, какие конкретные классы использует система. Другой скрывает, как экземпляры этих конкретных классов создаются и объединяются.
Пять хорошо известных шаблонов проектирования, которые являются частями шаблонов создания:
1. **Абстрактный шаблон фабрики** , который предоставляет интерфейс для создания связанных или зависимых объектов без указания конкретных классов объектов.
2. **Builder** , который отделяет построение сложного объекта от его представления, так что один и тот же процесс построения может создавать различные представления.
3. **Фабричный шаблон метода** , который позволяет классу переносить экземпляр на подклассы.
4. **Шаблон прототипа** , который определяет тип объекта для создания с использованием прототипического экземпляра и создает новые объекты, клонируя этот прототип.
5. **Singleton** , который гарантирует, что класс имеет только один экземпляр и предоставляет глобальную точку доступа к нему.
### источники
1. [Гамма, Эрих; Шлем, Ричард; Джонсон, Ральф; Влиссидес, Джон (1995). Шаблоны проектирования. Массачусетс: Эддисон-Уэсли. п. 81. ISBN 978-0-201-63361-0. Получено 2015-05-22.](http://www.pearsoned.co.uk/bookshop/detail.asp?item=171742)

View File

@@ -0,0 +1,27 @@
---
title: Algorithm Design Patterns
localeTitle: Шаблоны проектирования алгоритмов
---
## Шаблоны проектирования алгоритмов
В разработке программного обеспечения шаблон проектирования является общим повторяемым решением общей проблемы в разработке программного обеспечения. Шаблон проектирования не является готовым дизайном, который может быть преобразован непосредственно в код. Это описание или шаблон для решения проблемы, которая может использоваться во многих разных ситуациях.
Шаблоны проектирования могут ускорить процесс разработки, предоставив проверенные, проверенные парадигмы развития.
Эти шаблоны делятся на три основные категории:
### Создание шаблонов
Это шаблоны проектирования, которые касаются механизмов создания объектов, пытаясь создать объекты в соответствии с ситуацией. Основная форма создания объекта может привести к проблемам проектирования или сложности с дизайном. Создание шаблонов проектирования решает эту проблему, как-то контролируя создание этого объекта.
### Структурные структуры
Это шаблоны проектирования, которые облегчают дизайн, определяя простой способ реализации отношений между объектами.
### Поведенческие модели
Это шаблоны проектирования, которые идентифицируют общие шаблоны связи между объектами и реализуют эти шаблоны. Таким образом, эти шаблоны увеличивают гибкость при выполнении этого сообщения.
#### Дополнительная информация:
[Дизайн шаблонов - Википедия](https://en.wikipedia.org/wiki/Design_Patterns)

View File

@@ -0,0 +1,29 @@
---
title: Structural patterns
localeTitle: Структурные структуры
---
## Структурные структуры
Структурные шаблоны проектирования - это шаблоны проектирования, которые облегчают дизайн, определяя простой способ реализации отношений между сущностями и отвечают за построение простых и эффективных иерархий классов между различными классами.
Примеры структурных шаблонов включают:
1. **Шаблон адаптера** : «адаптирует» один интерфейс для класса в тот, который ожидает клиент.
2. **Конвейер** : используйте несколько адаптеров для целей отладки.
3. **Retrofit Interface Pattern** : адаптер, используемый в качестве нового интерфейса для нескольких классов одновременно.
4. **Агрегатный шаблон** : версия составного шаблона с методами агрегирования детей.
5. **Схема моста** : отделить абстракцию от ее реализации, чтобы они могли варьироваться независимо.
6. **Надгробный камень** : промежуточный объект «lookup» содержит реальное местоположение объекта.
7. **Композитный шаблон** : древовидная структура объектов, где каждый объект имеет один и тот же интерфейс.
8. **Рисунок декоратора** : добавьте дополнительные функциональные возможности для класса во время выполнения, когда подклассы приведут к экспоненциальному росту новых классов.
9. **Шаблон расширяемости** : aka Framework - скрыть сложный код за простым интерфейсом.
10. **Фасад** : создать упрощенный интерфейс существующего интерфейса для облегчения использования общих задач.
11. **Шаблон Flyweight** : большое количество объектов имеет общий объект свойств для экономии места.
12. **Шаблон маркера** : пустой интерфейс для связывания метаданных с классом.
13. **Трубы и фильтры** : цепочка процессов, где выход каждого процесса является входом следующего.
14. **Непрозрачный указатель** : указатель на необъявленный или закрытый тип, чтобы скрыть детали реализации.
15. **Прокси-шаблон** - класс, функционирующий как интерфейс к другому.
### источники
[https://en.wikipedia.org/wiki/Structural\_pattern](https://en.wikipedia.org/wiki/Structural_pattern)

View File

@@ -0,0 +1,93 @@
---
title: Algorithm Performance
localeTitle: Эффективность алгоритма
---
В математике обозначение Big-O является символом, используемым для описания и сравнения _предельного поведения_ функции.
Предельным поведением функции является то, как функция действует так, как она имеет тенденцию к определенному значению, и в примечании с большими О, обычно она имеет тенденцию к бесконечности.
Короче говоря, обозначение Big-O используется для описания роста или снижения функции, как правило, в отношении другой функции.
в дизайне алгоритма мы обычно используем нотацию большого О, потому что мы можем видеть, насколько плохой или хороший алгоритм будет работать в худшем режиме. но помните, что это не всегда так, потому что худший случай может быть очень редок, и в этих случаях мы вычисляем средний случай. на данный момент больше не упоминается.
В математике обозначение Big-O является символом, используемым для описания и сравнения _предельного поведения_ функции.
Предельным поведением функции является то, как функция действует так, как она имеет тенденцию к конкретному значению, и в примечаниях с большими О, обычно она имеет тенденцию к бесконечности.
Короче говоря, обозначение Big-O используется для описания роста или снижения функции, как правило, в отношении другой функции.
ПРИМЕЧАНИЕ: x ^ 2 эквивалентно x \* x или 'x-squared'\]
Например, мы говорим, что x = O (x ^ 2) для всех x> 1, или, другими словами, x ^ 2 является верхней границей по x и, следовательно, растет быстрее.
Символ утверждения типа x = O (x ^ 2) для всех x> _n_ можно заменить x <= x ^ 2 для всех x> _n,_ где _n_ - минимальное число, удовлетворяющее требованию, в этом случае 1.
Эффективно мы говорим, что функция f (x), то есть O (g (x)), растет медленнее, чем g (x).
Сравнительно, в информатике и разработке программного обеспечения мы можем использовать примечание «большой О», чтобы описать эффективность алгоритмов с помощью его временной и пространственной сложности.
**Космическая сложность** алгоритма относится к его размеру памяти относительно размера ввода.
В частности, при использовании записи с большим О мы описываем эффективность алгоритма по отношению к входу: _n_ , обычно по мере приближения _n_ к бесконечности.
При изучении алгоритмов мы обычно хотим снизить сложность времени и пространства. Сложность времени o (1) указывает на постоянное время.
Благодаря сравнению и анализу алгоритмов мы можем создавать более эффективные приложения.
Для производительности алгоритма мы имеем два основных фактора:
* **Время** : нам нужно знать, сколько времени требуется для запуска алгоритма для наших данных и как он будет расти по размеру данных (или в некоторых случаях других факторов, таких как количество цифр и т. Д.).
* **Пространство** : наша память - это финал, поэтому нам нужно знать, сколько свободного пространства нам нужно для этого алгоритма, и как время, которое нам нужно, чтобы проследить его рост.
Следующие 3 обозначения в основном используются для представления временной сложности алгоритмов:
1. **Θ Обозначение** : тета-нотация ограничивает функции сверху и снизу, поэтому определяет точное поведение. мы можем сказать, что мы имеем обозначение тета, когда наихудший случай и лучший случай одинаковы.
> Θ (g (n)) = {f (n): существуют положительные константы c1, c2 и n0 такие, что 0 <= c1 _g (n) <= f (n) <= c2_ g (n) для всех n> = n0}
2. **Big O Notation** : **нотация** Big O определяет верхнюю границу алгоритма. Например, Insertion Sort принимает линейное время в лучшем случае и квадратичное время в худшем случае. Мы можем с уверенностью сказать, что временная сложность сортировки Insertion равна _O_ ( _n ^ 2_ ).
> O (g (n)) = {f (n): существуют положительные константы c и n0 такие, что 0 <= f (n) <= cg (n) для всех n> = n0}
3. **Ω Обозначение** : **нотация** Ω обеспечивает нижнюю границу алгоритма. он показывает самый быстрый ответ для этого алгоритма. > Ω (g (n)) = {f (n): существуют положительные константы c и n0 такие, что 0 <= cg (n) <= f (n) для всех n> = n0}.
## Примеры
В качестве примера мы можем рассмотреть временную сложность алгоритма [\[пузырьковой сортировки\]](https://github.com/FreeCodeCamp/wiki/blob/master/Algorithms-Bubble-Sort.md#algorithm-bubble-sort) и выразить его с помощью записи с большими нотами.
#### Bubble Сортировать:
```javascript
// Function to implement bubble sort
void bubble_sort(int array<a href='http://bigocheatsheet.com/' target='_blank' rel='nofollow'>], int n)
{
// Here n is the number of elements in array
int temp;
for(int i = 0; i < n-1; i++)
{
// Last i elements are already in place
for(int j = 0; j < ni-1; j++)
{
if (array[j] > array[j+1])
{
// swap elements at index j and j+1
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
}
```
Посмотрев на этот код, мы видим, что в лучшем случае, когда массив уже отсортирован, программа будет делать только _n_ сравнения, поскольку никакие свопы не будут происходить.
Поэтому мы можем сказать, что наилучшая временная сложность сортировки пузырьков равна O ( _n_ ).
Изучая сценарий наихудшего случая, когда массив находится в обратном порядке, первая итерация будет производить _n_ сравнений, в то время как следующий должен будет сделать _n_ - 1 сравнений и т. Д., Пока не будет сделано только одно сравнение.
Таким образом, для этого случая обозначение Big-O имеет вид _n_ \* \[( _n_ - 1) / 2\], которое = 0,5 _n_ ^ 2 - 0,5 _n_ = O ( _n_ ^ 2), поскольку _n_ ^ 2 член доминирует над функцией, которая позволяет нам игнорировать другой член функции.
Мы можем подтвердить этот анализ с помощью \[этого удобного листа cheat Big-O, который отличается сложностью во времени большого количества часто используемых структур данных и алгоритмов
Очень очевидно, что в то время как для небольших случаев использования эта сложность времени может быть в порядке, при крупномасштабной сортировке пузырьков это просто нехорошее решение для сортировки.
Это мощь нотации O-O: она позволяет разработчикам легко увидеть потенциальные узкие места их приложения и предпринять шаги, чтобы сделать их более масштабируемыми.
Для получения дополнительной информации о том, почему важная нотация и анализ алгоритма важны, посетите этот [видеоролик](https://www.freecodecamp.com/videos/big-o-notation-what-it-is-and-why-you-should-care) !

View File

@@ -0,0 +1,52 @@
---
title: AVL Trees
localeTitle: Деревья AVL
---
## Деревья AVL
Дерево AVL является подтипом двоичного дерева поиска.
BST представляет собой структуру данных, состоящую из узлов. Он имеет следующие гарантии:
1. Каждое дерево имеет корневой узел (вверху).
2. Корневой узел имеет ноль или более дочерних узлов.
3. Каждый дочерний узел имеет ноль или более дочерних узлов и т. Д.
4. Каждый узел имеет до двух детей.
5. Для каждого узла его левые потомки меньше текущего узла, что меньше, чем у правых потомков.
У деревьев AVL есть дополнительная гарантия:
6. Разница между глубиной правого и левого поддеревьев не может быть больше одной. Чтобы сохранить эту гарантию, реализация AVL будет включать в себя алгоритм для балансировки дерева при добавлении дополнительного элемента, который нарушит эту гарантию.
Деревья AVL имеют наихудший поиск, вставку и удаление времени O (log n).
### Правильное вращение
![Правильное вращение дерева AVL](https://raw.githubusercontent.com/HebleV/valet_parking/master/images/avl_right_rotation.jpg)
### Левое вращение
![Левое вращение дерева AVL](https://raw.githubusercontent.com/HebleV/valet_parking/master/images/avl_left_rotation.jpg)
### Процесс вставки AVL
Вы сделаете вставку, похожую на обычную вставку двоичного поиска. После вставки вы исправляете свойство AVL с помощью поворота влево или вправо.
* Если есть дисбаланс в левом дочернем элементе правого поддерева, то вы выполняете поворот влево-вправо.
* Если есть дисбаланс в левом дочернем элементе левого поддерева, то вы выполняете правильное вращение.
* Если есть дисбаланс в правильном дочернем элементе правого поддерева, то вы выполняете левое вращение.
* Если есть дисбаланс в правом дочернем элементе левого поддерева, то вы выполняете правое-левое вращение.
#### Дополнительная информация:
[YouTube - AVL Tree](https://www.youtube.com/watch?v=7m94k2Qhg68)
Дерево AVL является самобалансирующимся двоичным деревом поиска. Дерево AVL представляет собой двоичное дерево поиска, которое имеет следующие свойства: -> Под деревья каждого узла отличаются высотой не более одного. -> Каждое поддерево является деревом AVL.
Дерево AVL проверяет высоту левого и правого поддеревьев и гарантирует, что разница не больше 1. Это различие называется коэффициентом баланса. Высота дерева AVL всегда равна O (Logn), где n - количество узлов в дереве.
Вращение дерева AVL: -
В дереве AVL после выполнения каждой операции, такой как вставка и удаление, нам нужно проверить коэффициент баланса каждого узла в дереве. Если каждый узел удовлетворяет условию баланса, то мы завершаем операцию, иначе мы должны сбалансировать ее. Мы используем операции поворота, чтобы дерево сбалансировалось всякий раз, когда дерево становится несбалансированным из-за какой-либо операции.
Операции вращения используются, чтобы сбалансировать дерево. Существует четыре оборота, и они подразделяются на два типа: -> Одиночное левое вращение (вращение LL) В LL Rotation каждый узел перемещает одну позицию влево от текущей позиции. -> Одиночное правое вращение (вращение RR) В RR Rotation каждый узел перемещает одну позицию вправо от текущей позиции. -> Вращение влево вправо (вращение LR) LR Rotation - комбинация одиночного левого вращения, за которым следует однократное вращение. В LR Rotation сначала каждый узел перемещает одну позицию влево, затем одну позицию вправо от текущей позиции. -> Вращение вправо влево (вращение RL) RL Rotation - комбинация одиночного правого вращения, за которым следует однократное вращение влево. В RL Rotation сначала каждый узел перемещает одну позицию вправо, затем одну позицию слева от текущей позиции.

View File

@@ -0,0 +1,15 @@
---
title: B Trees
localeTitle: B Деревья
---
## B Деревья
# Введение
B-Tree - это самобалансирующееся дерево поиска. В большинстве других самоустанавливающихся деревьев поиска (например, AVL и Red Black Trees) предполагается, что все в основной памяти. Чтобы понять использование B-деревьев, мы должны думать о огромном количестве данных, которые не могут вписываться в основную память. Когда число клавиш велико, данные считываются с диска в виде блоков. Время доступа к диску очень велико по сравнению с временем доступа к основной памяти. Основная идея использования B-Trees - уменьшить количество обращений к диску. Большинство операций с деревом (поиск, вставка, удаление, макс, мин, ..etc) требуют O (h) доступа к диску, где h - высота дерева. B-дерево - жирное дерево. Высота B-деревьев поддерживается на низком уровне, помещая максимально возможные ключи в узел B-Tree. Как правило, размер узла B-Tree поддерживается равным размеру блока диска. Так как h для B-Tree является низким, общий доступ к диску для большинства операций значительно уменьшается по сравнению с сбалансированными двоичными деревьями поиска, такими как AVL Tree, Red Black Tree, ..etc.
Свойства B-Tree: 1) Все листья находятся на одном уровне. 2) B-Tree определяется термином «минимальная степень» t. Значение t зависит от размера блока диска. 3) Каждый узел, кроме root, должен содержать не менее t-1 ключей. Корень может содержать минимум 1 ключ. 4) Все узлы (включая корень) могут содержать не более 2 т - 1 ключей. 5) Число дочерних узлов узла равно числу ключей в нем плюс 1. 6) Все ключи узла сортируются в порядке возрастания. Ребенок между двумя ключами k1 и k2 содержит все клавиши в диапазоне от k1 и k2. 7) B-Tree растет и сжимается от корня, что не похоже на двоичное дерево поиска. Деревья двоичного поиска растут вниз, а также сокращаются вниз. 8) Как и другие сбалансированные двоичные деревья поиска, сложность времени поиска, вставки и удаления - O (Logn).
Поиск: Поиск аналогичен поиску в двоичном дереве поиска. Пусть ключ, подлежащий поиску, будет k. Мы начинаем с корня и рекурсивно переходим вниз. Для каждого посещенного нелистового узла, если узел имеет ключ, мы просто возвращаем узел. В противном случае мы возвращаемся к соответствующему дочернему элементу (дочернему, который находится непосредственно перед первым большим ключом) узла. Если мы достигнем листового узла и не найдем k в листовом узле, мы возвращаем NULL.
Траверс: Обход также похож на обход двоичного дерева. Мы начинаем с самого левого ребенка, рекурсивно печатаем самого левого ребенка, затем повторяем тот же процесс для оставшихся детей и ключей. В итоге рекурсивно напечатайте самый правый ребенок.

View File

@@ -0,0 +1,53 @@
---
title: Backtracking Algorithms
localeTitle: Алгоритмы обратного слежения
---
# Алгоритмы обратного слежения
Backtracking - это общий алгоритм поиска всех (или некоторых) решений некоторых вычислительных задач, в частности ограничение проблем с удовлетворенностью, который постепенно создает кандидатов в решения и отказывается от каждого частичного кандидата _(«backtracks»),_ как только он определяет, что кандидат не может возможно, будет завершено до действительного решения.
### Пример проблемы (проблема с рыцарским туром)
_Рыцарь помещается в первый блок пустой доски и, перемещаясь по правилам шахмат, должен посещать каждый квадрат ровно один раз._
\### Путь, за которым следует Рыцарь, чтобы охватить все ячейки Ниже показана шахматная доска с 8 x 8 ячейками. Числа в ячейках указывают количество движения рыцаря. [![Турнирное решение рыцаря - Эйлером](https://upload.wikimedia.org/wikipedia/commons/d/df/Knights_tour_%28Euler%29.png)](https://commons.wikimedia.org/wiki/File:Knights_tour_(Euler).png)
### Наивный алгоритм для рыцарского тура
Наивный алгоритм состоит в том, чтобы генерировать все туры по одному и проверять, удовлетворяет ли сгенерированный тур по ограничениям.
```
while there are untried tours
{
generate the next tour
if this tour covers all squares
{
print this path;
}
}
```
### Алгоритм обратной трассировки для рыцарского тура
Ниже приведен алгоритм Backtracking для проблемы тура Knight.
```
If all squares are visited
print the solution
Else
a) Add one of the next moves to solution vector and recursively
check if this move leads to a solution. (A Knight can make maximum
eight moves. We choose one of the 8 moves in this step).
b) If the move chosen in the above step doesn't lead to a solution
then remove this move from the solution vector and try other
alternative moves.
c) If none of the alternatives work then return false (Returning false
will remove the previously added item in recursion and if false is
returned by the initial call of recursion then "no solution exists" )
```
### Больше информации
[Википедия](https://en.wikipedia.org/wiki/Backtracking)
[Geeks 4 Geeks](http://www.geeksforgeeks.org/backtracking-set-1-the-knights-tour-problem/)
[Очень интересное введение в откат](https://www.hackerearth.com/practice/basic-programming/recursion/recursion-and-backtracking/tutorial/)

View File

@@ -0,0 +1,269 @@
---
title: Binary Search Trees
localeTitle: Деревья двоичного поиска
---
## Деревья двоичного поиска
![Двоичное дерево поиска](https://cdn-images-1.medium.com/max/1320/0*x5o1G1UpM1RfLpyx.png)
Дерево представляет собой структуру данных, состоящую из узлов, которые имеют следующие характеристики:
1. Каждое дерево имеет корневой узел (вверху), имеющий некоторое значение.
2. Корневой узел имеет ноль или более дочерних узлов.
3. Каждый дочерний узел имеет ноль или более дочерних узлов и т. Д. Это создает поддерево в дереве. Каждый узел имеет свое собственное поддерево, состоящее из его детей и их детей и т. Д. Это означает, что каждый узел сам по себе может быть деревом.
Двоичное дерево поиска (BST) добавляет эти две характеристики:
1. Каждый узел имеет максимум до двух детей.
2. Для каждого узла значения его левых узлов-потомков меньше, чем у текущего узла, который, в свою очередь, меньше, чем правые узлы-потомки (если они есть).
BST построен на идее алгоритма [бинарного поиска](https://guide.freecodecamp.org/algorithms/search-algorithms/binary-search) , который позволяет быстро находить, вставлять и удалять узлы. Способ их настройки означает, что в среднем каждое сравнение позволяет операциям пропускать около половины дерева, так что каждый поиск, вставка или удаление занимает время, пропорциональное логарифму количества элементов, хранящихся в дереве, `O(log n)` . Однако иногда может произойти худший случай, когда дерево не сбалансировано, а временная сложность `O(n)` для всех трех этих функций. Вот почему самобалансирующиеся деревья (AVL, red-black и т. Д.) Намного эффективнее базового BST.
**Пример худшего сценария:** это может произойти, когда вы добавляете узлы, которые сегда_ больше, чем узел (родительский), то же самое может произойти, когда вы всегда добавляете узлы со значениями ниже своих родителей.
### Основные операции на BST
* Create: создает пустое дерево.
* Вставить: вставить узел в дерево.
* Поиск: поиск узла в дереве.
* Удалить: удаляет узел из дерева.
#### Создайте
Сначала создается пустое дерево без каких-либо узлов. Переменная / идентификатор, который должен указывать на корневой узел, инициализируется значением `NULL` .
#### Поиск
Вы всегда начинаете искать дерево в корневом узле и спускаетесь оттуда. Вы сравниваете данные в каждом узле с тем, который вы ищете. Если сравниваемый узел не совпадает, вы либо переходите к правильному ребенку, либо к левому ребенку, что зависит от результата следующего сравнения: если узел, который вы ищете, меньше, чем тот, с которым вы сравнивали его, вы переходите к левому ребенку, иначе (если он больше) вы переходите к правильному ребенку. Зачем? Поскольку BST структурирован (согласно его определению), что правильный ребенок всегда больше родителя, а левый ребенок всегда меньше.
#### Вставить
Он очень похож на функцию поиска. Вы снова начинаете с корня дерева и возвращаетесь рекурсивно, ища подходящее место для вставки нашего нового узла так же, как описано в функции поиска. Если узел с тем же значением уже находится в дереве, вы можете выбрать либо вставить дубликат, либо нет. Некоторые деревья допускают дубликаты, некоторые - нет. Это зависит от определенной реализации.
#### делеция
Есть три случая, которые могут произойти, когда вы пытаетесь удалить узел. Если это так,
1. Нет поддерева (без детей): этот самый простой. Вы можете просто удалить узел без каких-либо дополнительных действий.
2. Одно поддерево (один ребенок): вы должны убедиться, что после удаления узла его дочерний элемент затем подключается к родительскому элементу удаленного узла.
3. Два поддерева (двое детей): вы должны найти и заменить узел, который хотите удалить, с его преемником (letfmost node в правом поддереве).
Сложность времени для создания дерева - `O(1)` . Сложность времени для поиска, вставки или удаления узла зависит от высоты дерева `h` , поэтому худшим случаем является `O(h)` .
#### Предшественник узла
Предшественники можно охарактеризовать как узел, который появится прямо перед узлом, в котором вы сейчас находитесь. Чтобы найти предшественника текущего узла, посмотрите на правый / самый большой листовой узел в левом поддереве.
#### Преемник узла
Преемники можно охарактеризовать как узел, который появится сразу после узла, в котором вы сейчас находитесь. Чтобы найти преемника текущего узла, посмотрите на самый левый или самый маленький листовой узел в правом поддереве.
### Специальные типы BT
* отвал
* Красно-черное дерево
* В-дерево
* Splay tree
* N-арное дерево
* Trie (дерево Radix)
### время выполнения
**Структура данных: массив**
* Наихудшая производительность: `O(log n)`
* Лучшая производительность: `O(1)`
* Средняя производительность: `O(log n)`
* Сложная сложность пространства: `O(1)`
Где `n` - количество узлов в BST.
### Внедрение BST
Вот определение для узла BST, имеющего некоторые данные, ссылающиеся на его левый и правый дочерние узлы.
```c
struct node {
int data;
struct node *leftChild;
struct node *rightChild;
};
```
#### Операция поиска
Всякий раз, когда элемент нужно искать, начните поиск с корневого узла. Затем, если данные меньше значения ключа, выполните поиск элемента в левом поддереве. В противном случае выполните поиск элемента в правом поддереве. Следуйте одному и тому же алгоритму для каждого узла.
```c
struct node* search(int data){
struct node *current = root;
printf("Visiting elements: ");
while(current->data != data){
if(current != NULL) {
printf("%d ",current->data);
//go to left tree
if(current->data > data){
current = current->leftChild;
}//else go to right tree
else {
current = current->rightChild;
}
//not found
if(current == NULL){
return NULL;
}
}
}
return current;
}
```
#### Вставить операцию
Всякий раз, когда элемент должен быть вставлен, сначала найдите его правильное местоположение. Начните поиск с корневого узла, затем, если данные меньше значения ключа, найдите пустое место в левом поддереве и вставьте данные. В противном случае найдите пустое место в правом поддереве и вставьте данные.
```c
void insert(int data) {
struct node *tempNode = (struct node*) malloc(sizeof(struct node));
struct node *current;
struct node *parent;
tempNode->data = data;
tempNode->leftChild = NULL;
tempNode->rightChild = NULL;
//if tree is empty
if(root == NULL) {
root = tempNode;
} else {
current = root;
parent = NULL;
while(1) {
parent = current;
//go to left of the tree
if(data < parent->data) {
current = current->leftChild;
//insert to the left
if(current == NULL) {
parent->leftChild = tempNode;
return;
}
}//go to right of the tree
else {
current = current->rightChild;
//insert to the right
if(current == NULL) {
parent->rightChild = tempNode;
return;
}
}
}
}
}
```
Двоичные деревья поиска (BST) также дают нам быстрый доступ к предшественникам и преемникам. Предшественники можно охарактеризовать как узел, который появится прямо перед узлом, в котором вы сейчас находитесь.
* Чтобы найти предшественника текущего узла, посмотрите на самый правый / самый большой листовой узел в левом поддереве. Преемники можно охарактеризовать как узел, который появится сразу после узла, в котором вы сейчас находитесь.
* Чтобы найти преемника текущего узла, посмотрите на самый левый / самый маленький листовой узел в правом поддереве.
### Давайте посмотрим на пару процедур, работающих на деревьях.
Поскольку деревья рекурсивно определены, очень часто приходится писать процедуры, которые работают на деревьях, которые сами являются рекурсивными.
Например, если мы хотим рассчитать высоту дерева, то есть высоту корневого узла, мы можем идти вперед и рекурсивно делать это, проходя через дерево. Поэтому мы можем сказать:
* Например, если у нас есть дерево nil, то его высота равна 0.
* В противном случае мы достигнем 1 плюс максимум левого дочернего дерева и правого дочернего дерева.
* Поэтому, если мы посмотрим на лист, например, эта высота будет равна 1, так как высота левого дочернего элемента равна нулю, равно 0, а высота нулевого правильного ребенка равна 0. Таким образом, максимальная величина равна 0, затем 1 плюс 0.
#### Алгоритм высоты (дерева)
```
if tree = nil:
return 0
return 1 + Max(Height(tree.left),Height(tree.right))
```
#### Вот код в C ++
```
int maxDepth(struct node* node)
{
if (node==NULL)
return 0;
else
{
int rDepth = maxDepth(node->right);
int lDepth = maxDepth(node->left);
if (lDepth > rDepth)
{
return(lDepth+1);
}
else
{
return(rDepth+1);
}
}
}
```
Мы могли бы также посмотреть на вычисление размера дерева, которое является числом узлов.
* Опять же, если у нас есть дерево nil, у нас есть нулевые узлы.
* В противном случае мы имеем число узлов в левом дочернем элементе плюс 1 для себя плюс число узлов в правом дочернем элементе. Итак, 1 плюс размер левого дерева плюс размер правильного дерева.
#### Алгоритм размера (дерева)
```
if tree = nil
return 0
return 1 + Size(tree.left) + Size(tree.right)
```
#### Вот код в C ++
```
int treeSize(struct node* node)
{
if (node==NULL)
return 0;
else
return 1+(treeSize(node->left) + treeSize(node->right));
}
```
### Соответствующие видео на канале freeCodeCamp YouTube
* [Двоичное дерево поиска](https://youtu.be/5cU1ILGy6dM)
* [Двоичное дерево поиска: обход и высота](https://youtu.be/Aagf3RyK3Lw)
### Ниже приведены общие типы двоичных деревьев:
Полное двоичное дерево / строковое двоичное дерево: двоичное дерево является полным или строгим, если каждый узел имеет ровно 0 или 2 детей.
```
18
/ \
15 30
/ \ / \
40 50 100 40
```
В полном двоичном дереве количество листовых узлов равно числу внутренних узлов плюс один.
Полное двоичное дерево: двоичное дерево является полным двоичным деревом, если все уровни полностью заполнены, за исключением, возможно, последнего уровня, а последний уровень имеет все ключи как можно дальше
```
18
/ \
15 30
/ \ / \
40 50 100 40
/ \ /
8 7 9
```

View File

@@ -0,0 +1,43 @@
---
title: Boundary Fill
localeTitle: Граничная заливка
---
## Граничная заливка
Граничная заливка - это алгоритм, часто используемый в компьютерной графике для заполнения нужного цвета внутри замкнутого многоугольника с той же границей цвет для всех его сторон.
Наиболее подходящей реализацией алгоритма является рекурсивная функция на основе стека.
### За работой:
Проблема довольно проста и обычно следует следующим шагам:
1. Возьмите позицию начальной и граничной окраски.
2. Решите, хотите ли вы идти в 4 направлениях (N, S, W, E) или 8 направлений (N, S, W, E, NW, NE, SW, SE).
3. Выберите цвет заливки.
4. Путешествуйте в этих направлениях.
5. Если пиксель, на который вы попали, не является цветом заливки или граничным цветом, замените его цветом заливки.
6. Повторяйте 4 и 5, пока не повсюду в пределах границ.
### Определенные ограничения:
* Граничный цвет должен быть одинаковым для всех краев многоугольника.
* Отправная точка должна быть в пределах многоугольника.
### Фрагмент кода:
```
void boundary_fill(int pos_x, int pos_y, int boundary_color, int fill_color)
{
current_color= getpixel(pos_x,pos_y); //get the color of the current pixel position
if( current_color!= boundary_color || currrent_color != fill_color) // if pixel not already filled or part of the boundary then
{
putpixel(pos_x,pos_y,fill_color); //change the color for this pixel to the desired fill_color
boundary_fill(pos_x + 1, pos_y,boundary_color,fill_color); // perform same function for the east pixel
boundary_fill(pos_x - 1, pos_y,boundary_color,fill_color); // perform same function for the west pixel
boundary_fill(pos_x, pos_y + 1,boundary_color,fill_color); // perform same function for the north pixel
boundary_fill(pos_x, pos_y - 1,boundary_color,fill_color); // perform same function for the south pixel
}
}
```
Из данного кода вы можете видеть, что для любого пикселя, на который вы приземляетесь, вы сначала проверяете, можно ли его изменить на fill\_color, а затем вы это сделаете для его соседей, пока не будут проверены все пиксели в пределах границы.

View File

@@ -0,0 +1,17 @@
---
title: Brute Force Algorithms
localeTitle: Алгоритмы грубой силы
---
## Алгоритмы грубой силы
Алгоритмы Brute Force ссылаются на стиль программирования, который не содержит ярлыков для повышения производительности, но вместо этого полагается на полную вычислительную мощность, чтобы попробовать все возможности, пока не будет найдено решение проблемы.
Классическим примером является проблема коммивояжера (TSP). Предположим, что продавец должен посетить 10 городов по всей стране. Как определить порядок, в котором следует посещать города, чтобы минимизировать общее пройденное расстояние? Решение грубой силы просто вычисляет общее расстояние для каждого возможного маршрута, а затем выбирает самый короткий. Это не особенно эффективно, потому что можно устранить множество возможных маршрутов с помощью умных алгоритмов.
Другой пример: 5-значный пароль, в худшем случае - 10 5 попыток взлома.
Сложность времени грубой силы равна **O (n \* m)** . Итак, если бы мы искали строку из «n» символов в строке символов «m» с использованием грубой силы, это потребовало бы n \* m попыток.
#### Дополнительная информация:
[Википедия](https://en.wikipedia.org/wiki/Brute-force_search)

View File

@@ -0,0 +1,33 @@
---
title: Divide and Conquer Algorithms
localeTitle: Разделить и покорить алгоритмы
---
## Разделить и покорить алгоритмы
Разделить и покорить | (Вступление) Подобно Greedy и Dynamic Programming, Divide and Conquer - алгоритмическая парадигма. Типичный алгоритм Divide и Conquer решает проблему, используя следующие три шага.
1. Разделить: разбить данную проблему на подзадачи того же типа.
2. Conquer: рекурсивно решать эти подзадачи
3. Комбинат: надлежащим образом объедините ответы
Ниже приведены некоторые стандартные алгоритмы, которые являются алгоритмами Divide и Conquer.
1) Бинарный поиск - это алгоритм поиска. На каждом шаге алгоритм сравнивает входной элемент x со значением среднего элемента в массиве. Если значения совпадают, верните индекс из середины. В противном случае, если x меньше среднего элемента, тогда алгоритм повторяется для левой части среднего элемента, а другой - для правой части среднего элемента.
2) Quicksort - это алгоритм сортировки. Алгоритм выбирает элемент поворота, перестраивает элементы массива таким образом, что все элементы, меньшие, чем выбранный элемент поворота, перемещаются влево от оси вращения, а все более крупные элементы перемещаются в правую сторону. Наконец, алгоритм рекурсивно сортирует подмассивы слева и справа от элемента поворота.
3) Merge Sort также является алгоритмом сортировки. Алгоритм делит массив на две половины, рекурсивно сортирует их и, наконец, объединяет две отсортированные половинки.
4) Ближайшая пара точек Задача состоит в том, чтобы найти ближайшую пару точек в множестве точек в плоскости xy. Задача может быть решена в O (n ^ 2) раз, вычисляя расстояния каждой пары точек и сравнивая расстояния для нахождения минимума. Алгоритм Divide и Conquer решает проблему в O (nLogn) времени.
5) Алгоритм Штрассена - эффективный алгоритм умножения двух матриц. Простым методом для умножения двух матриц требуется 3 вложенных цикла и O (n ^ 3). Алгоритм Штрассена умножает две матрицы в O (n ^ 2.8974).
6) Алгоритм быстрого преобразования Фурье Кули-Туки - наиболее распространенный алгоритм БПФ. Это алгоритм разделения и покоя, который работает в O (nlogn) времени.
7) Алгоритм Карацубы был первым алгоритмом умножения асимптотически быстрее, чем квадратичный алгоритм «классной школы». Это уменьшает умножение двух n-разрядных чисел на максимум до n ^ 1,585 (что является приближением к log 3 в базе 2) однозначных продуктов. Поэтому он быстрее, чем классический алгоритм, который требует n ^ 2 однозначных продуктов.
### Divide and Conquer (D & C) и динамическое программирование (DP)
Обе парадигмы (D & C и DP) делят данную проблему на подзадачи и решают подзадачи. Как выбрать один из них для данной проблемы? Divide и Conquer следует использовать, когда одни и те же подзадачи не оцениваются много раз. В противном случае следует использовать динамическое программирование или памятку.
Например, Binary Search - это алгоритм Divide и Conquer, мы никогда не оцениваем одни и те же подзадачи снова. С другой стороны, для вычисления n-го числа Фибоначчи должно быть предпочтительным динамическое программирование.

View File

@@ -0,0 +1,16 @@
---
title: Embarassingly Parallel Algorithms
localeTitle: Эмбирирующие параллельные алгоритмы
---
## Эмбирирующие параллельные алгоритмы
При параллельном программировании неловко параллельным алгоритмом является тот, который не требует связи или зависимости между процессами. В отличие от распределенных вычислительных задач, требующих связи между задачами, особенно на промежуточных результатах, смущающие параллельные алгоритмы легко выполнять на фермах серверов, которым не хватает специальной инфраструктуры, используемой в истинном суперкомпьютерном кластере. Из-за характера смущающих параллельных алгоритмов они хорошо подходят для больших распределенных платформ на базе Интернета и не страдают от параллельного замедления. Противоположностью неловко параллельных проблем являются, по сути, серийные проблемы, которые не могут быть распараллелены вообще. Идеальный случай смущающих параллельных алгоритмов можно резюмировать следующим образом:
* Все подзадачи или задачи определены до начала вычислений.
* Все подрешения хранятся в независимых ячейках памяти (переменные, элементы массива).
* Таким образом, вычисление подрешений полностью независимо.
* Если вычисления требуют некоторой начальной или окончательной связи, мы называем это почти неловко параллельным.
Многие могут задаться вопросом о этимологии термина «смущающе». В этом случае, смущающе не имеет ничего общего с смущением; на самом деле это означает переизбыток - здесь речь идет о проблемах с параллелизацией, которые «смущающе легки».
Общим примером неловко параллельной проблемы является обработка 3D-видео, обрабатываемая блоком обработки графики, где каждый кадр или пиксель можно обрабатывать без взаимозависимости. Некоторые другие примеры - это программное обеспечение для сгибания белков, которое может работать на любом компьютере, причем каждая машина выполняет небольшую часть работы, генерирует все подмножества, случайные числа и моделирование методом Монте-Карло.

View File

@@ -0,0 +1,11 @@
---
title: Evaluating Polynomials Direct Analysis
localeTitle: Оценка прямого анализа полиномов
---
## Оценка прямого анализа полиномов
Это заглушка. [Помогите нашему сообществу расширить его](https://github.com/freecodecamp/guides/tree/master/src/pages/algorithms/evaluating-polynomials-direct-analysis/index.md) .
[Это руководство по быстрому стилю поможет вам принять ваш запрос на тягу](https://github.com/freecodecamp/guides/blob/master/README.md) .
#### Дополнительная информация:

View File

@@ -0,0 +1,11 @@
---
title: Evaluating Polynomials Synthetic Division
localeTitle: Оценка синтетического отдела полиномов
---
## Оценка синтетического отдела полиномов
Это заглушка. [Помогите нашему сообществу расширить его](https://github.com/freecodecamp/guides/tree/master/src/pages/algorithms/evaluating-polynomials-synthetic-division/index.md) .
[Это руководство по быстрому стилю поможет вам принять ваш запрос на тягу](https://github.com/freecodecamp/guides/blob/master/README.md) .
#### Дополнительная информация:

View File

@@ -0,0 +1,61 @@
---
title: Exponentiation
localeTitle: Возведение
---
## Возведение
Для двух целых чисел a и n, напишите функцию для вычисления a ^ n.
#### Код
Алгоритмическая парадигма: разделите и покорите.
```C
int power(int x, unsigned int y) {
if (y == 0)
return 1;
else if (y%2 == 0)
return power(x, y/2)*power(x, y/2);
else
return x*power(x, y/2)*power(x, y/2);
}
```
Сложность времени: O (n) | Космическая сложность: O (1)
#### Оптимизированное решение: O (logn)
```C
int power(int x, unsigned int y) {
int temp;
if( y == 0)
return 1;
temp = power(x, y/2);
if (y%2 == 0)
return temp*temp;
else
return x*temp*temp;
}
```
## Модульное возведение в степень
Учитывая три числа x, y и p, вычислить (x ^ y)% p
```C
int power(int x, unsigned int y, int p) {
int res = 1;
x = x % p;
while (y > 0) {
if (y & 1)
res = (res*x) % p;
// y must be even now
y = y>>1;
x = (x*x) % p;
}
return res;
}
```
Сложность времени: O (Log y).

View File

@@ -0,0 +1,100 @@
---
title: Flood Fill Algorithm
localeTitle: Алгоритм заполнения паводков
---
## Алгоритм заполнения паводков
Flood fill - это алгоритм, используемый в основном для определения ограниченной области, связанной с данным узлом в многомерном массиве. это близкое сходство с инструментом ковша в программах рисования.
Наиболее подходящая реализация алгоритма представляет собой рекурсивную функцию на основе стека, и об этом мы поговорим следующий.
### Как это работает?
Проблема довольно проста и обычно следует следующим шагам:
1. Возьмите позицию начальной точки.
2. Решите, хотите ли вы идти в 4 направлениях ( **N, S, W, E** ) или 8 направлений ( **N, S, W, E, NW, NE, SW, SE** ).
3. Выберите цвет замены и целевой цвет.
4. Путешествуйте в этих направлениях.
5. Если плитка, на которой вы приземляетесь, является мишенью, используйте ее с выбранным цветом.
6. Повторяйте 4 и 5, пока не повсюду в пределах границ.
Возьмем в качестве примера следующий массив:
![alt text](https://github.com/firealex2/Codingame/blob/master/small%208%20grid%20paintefffd.png)
Красный квадрат - это начальная точка, а серые квадраты - это так называемые стены.
Для получения дополнительной информации, вот фрагмент кода, описывающий функцию:
```c++
int wall = -1;
void flood_fill(int pos_x, int pos_y, int target_color, int color)
{
if(a[pos_x][pos_y] == wall || a[pos_x][pos_y] == color) // if there is no wall or if i haven't been there
return; // already go back
if(a[pos_x][pos_y] != target_color) // if it's not color go back
return;
a[pos_x][pos_y] = color; // mark the point so that I know if I passed through it.
flood_fill(pos_x + 1, pos_y, color); // then i can either go south
flood_fill(pos_x - 1, pos_y, color); // or north
flood_fill(pos_x, pos_y + 1, color); // or east
flood_fill(pos_x, pos_y - 1, color); // or west
return;
}
```
Как видно выше, отправной точкой является (4,4). После вызова функции для начальных координат **x = 4** и **y = 4** , Я могу начать проверять, нет ли стены или цвета на месте. Если это действительно, я отмечаю пятно одним **«цветным» цветом,** и начните проверять другие квадраты adiacent.
Подойдя к югу, мы перейдем к пункту (5,4), и функция снова запустится.
### Проблема с физической нагрузкой
Я всегда считал, что решение (или более) проблемы / с использованием недавно выученного алгоритма - лучший способ полностью понять концепт.
Итак, вот что:
**Утверждение:**
В двумерном массиве вам предоставляется n число **«островов»** . Попытайтесь найти самую большую площадь острова и соответствующий остров число. 0 обозначает воду и любые другие х между 1 и n отмечает один квадрат от поверхности, соответствующей на остров х.
**вход**
* **n** - количество островов.
* **l, c** - размеры матрицы.
* следующие **l** строк, **c** чисел, дающих **l-** ю строку матрицы.
**Выход**
* **i** - номер острова с наибольшей площадью.
* **A** - площадь **i** -го острова.
**Пример:**
У вас есть следующий ввод:
```c++
2 4 4
0 0 0 1
0 0 1 1
0 0 0 2
2 2 2 2
```
Для чего вы получите остров нет. 2 как самый большой остров площадью 5 квадратов.
### Советы
Проблема довольно проста, но вот несколько советов:
```
1. Use the flood-fill algorithm whenever you encounter a new island.
2. As opposed to the sample code, you should go through the area of the island and not on the ocean (0 tiles).
```

View File

@@ -0,0 +1,125 @@
---
title: Breadth First Search (BFS)
localeTitle: Первый поиск Breadth (BFS)
---
## Первый поиск Breadth (BFS)
Breadth First Search - один из самых простых алгоритмов графа. Он пересекает график, сначала проверяя текущий узел, а затем расширяя его, добавляя своих преемников на следующий уровень. Процесс повторяется для всех узлов текущего уровня, прежде чем перейти на следующий уровень. Если решение найдено, поиск останавливается.
### Визуализация
![](https://upload.wikimedia.org/wikipedia/commons/4/46/Animated_BFS.gif)
### оценка
Космическая сложность: O (n)
Хуже того, сложность времени: O (n)
Breadth First Search завершен на конечном множестве узлов и оптимален, если стоимость перехода от одного узла к другому постоянна.
### Код C ++ для реализации BFS
```cpp
// Program to print BFS traversal from a given
// source vertex. BFS(int s) traverses vertices
// reachable from s.
#include<iostream>
#include <list>
using namespace std;
// This class represents a directed graph using
// adjacency list representation
class Graph
{
int V; // No. of vertices
// Pointer to an array containing adjacency
// lists
list<int> *adj;
public:
Graph(int V); // Constructor
// function to add an edge to graph
void addEdge(int v, int w);
// prints BFS traversal from a given source s
void BFS(int s);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v's list.
}
void Graph::BFS(int s)
{
// Mark all the vertices as not visited
bool *visited = new bool[V];
for(int i = 0; i < V; i++)
visited[i] = false;
// Create a queue for BFS
list<int> queue;
// Mark the current node as visited and enqueue it
visited[s] = true;
queue.push_back(s);
// 'i' will be used to get all adjacent
// vertices of a vertex
list<int>::iterator i;
while(!queue.empty())
{
// Dequeue a vertex from queue and print it
s = queue.front();
cout << s << " ";
queue.pop_front();
// Get all adjacent vertices of the dequeued
// vertex s. If a adjacent has not been visited,
// then mark it visited and enqueue it
for (i = adj[s].begin(); i != adj[s].end(); ++i)
{
if (!visited[*i])
{
visited[*i] = true;
queue.push_back(*i);
}
}
}
}
// Driver program to test methods of graph class
int main()
{
// Create a graph given in the above diagram
Graph g(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
cout << "Following is Breadth First Traversal "
<< "(starting from vertex 2) \n";
g.BFS(2);
return 0;
}
```
#### Дополнительная информация:
[диаграммы](https://github.com/freecodecamp/guides/computer-science/data-structures/graphs/index.md)
[Глубина первого поиска (DFS)](https://github.com/freecodecamp/guides/tree/master/src/pages/algorithms/graph-algorithms/depth-first-search/index.md)

View File

@@ -0,0 +1,105 @@
---
title: Depth First Search (DFS)
localeTitle: Глубина первого поиска (DFS)
---
## Глубина первого поиска (DFS)
Depth First Search - один из самых простых алгоритмов графа. Он пересекает график, сначала проверяя текущий узел, а затем переходя к одному из его помощников, чтобы повторить процесс. Если в текущем узле нет помощника для проверки, мы возвращаемся к его предшественнику, и процесс продолжается (перейдя к другому помощнику). Если решение найдено, поиск останавливается.
### Визуализация
![](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)
### Реализация (C ++ 14)
\`\` \`C ++
# включают
# включают
# включают
# включают
использование пространства имен std;
класс Graph { на телевидении; // количество вершин
```
// pointer to a vector containing adjacency lists
vector < int > *adj;
```
общественности: График (int v); // Конструктор
```
// function to add an edge to graph
void add_edge(int v, int w);
// prints dfs traversal from a given source `s`
void dfs();
void dfs_util(int s, vector < bool> &visited);
```
};
Graph :: Graph (int v) { это -> v = v; adj = новый вектор <int> \[v\]; }
void Graph :: add _edge (int u, int v) { adj \[u\] .push_ назад (v); // добавьте v в список u adj \[v\] .push азад (v); // добавим u в список v (удалите этот оператор, если график направлен!) } void Graph :: dfs () { // посещаемый вектор - отслеживать посещаемые узлы во время DFS вектор <bool> посещен (v, false); // маркировка всех узлов / вершин как не посещенных for (int i = 0; i <v; i ++) если (! посещаемые \[я\]) dfs_ util (i, посещенный); } // обратите внимание на использование вызова по ссылке здесь! void Graph :: dfs\_util (int s, vector <bool> & visited) { // пометить текущий узел / вершину как посещенный \[s\] = true; // выводим его на стандартный вывод (экран) cout << s << "";
```
// traverse its adjacency list and recursively call dfs_util for all of its neighbours!
// (only if the neighbour has not been visited yet!)
for(vector < int > :: iterator itr = adj[s].begin(); itr != adj[s].end(); itr++)
if(!visited[*itr])
dfs_util(*itr, visited);
```
}
int main () { // создаем граф, используя класс Graph, который мы определили выше График g (4); g.add _edge (0, 1); g.add_ edge (0, 2); g.add _edge (1, 2); g.add_ edge (2, 0); g.add _edge (2, 3); g.add_ edge (3, 3);
```
cout << "Following is the Depth First Traversal of the provided graph"
<< "(starting from vertex 0): ";
g.dfs();
// output would be: 0 1 2 3
return 0;
```
}
```
### Evaluation
Space Complexity: O(n)
Worse Case Time Complexity: O(n)
Depth First Search is complete on a finite set of nodes. I works better on shallow trees.
### Implementation of DFS in C++
```
C ++
# включают
# включают
# включают
использование пространства имен std;
struct Graph { на телевидении; bool \* _adj; общественности: График (int vcount); void addEdge (int u, int v); void deleteEdge (int u, int v); вектор_ _DFS (int s); void DFSUtil (int s, vector_ _& ДФС, вектор_ _и посетил); }; Graph :: Graph (int vcount) { this-> v = vcount; this-> adj = new bool_ \[vcount\]; для (int i = 0; i
void Graph :: addEdge (int u, int w) { this-> прил \[и\] \[ш\] = TRUE; this-> прил \[ш\] \[и\] = TRUE; }
void Graph :: deleteEdge (int u, int w) { this-> прил \[и\] \[ш\] = ложь; this-> прил \[ж\] \[и\] = ложь; }
void Graph :: DFSUtil (int s, vector & dfs, вектор И посетил) { посетил \[с\] = TRUE; dfs.push\_back (ы); для (int i = 0; i v; я ++) { if (this-> adj \[s\] \[i\] == true && visited \[i\] == false) Dfsutil (я, ДФС, посетил); } }
вектор Graph :: DFS (int s) { вектор посетил (this-> v); вектор ДФС; Dfsutil (s, ДФС, посетили); return dfs; } \`\` \`
#### Дополнительная информация:
[диаграммы](https://github.com/freecodecamp/guides/computer-science/data-structures/graphs/index.md)
[Первый поиск Breadth (BFS)](https://github.com/freecodecamp/guides/tree/master/src/pages/algorithms/graph-algorithms/breadth-first-search/index.md)
[Глубина первого поиска (DFS) - Википедия](https://en.wikipedia.org/wiki/Depth-first_search)

View File

@@ -0,0 +1,95 @@
---
title: Dijkstra's Algorithm
localeTitle: Алгоритм Дейкстры
---
# Алгоритм Дейкстры
Алгоритм Дейкстры - это алгоритм графа, представленный Е. В. Дейкстром. Он находит кратчайший путь одного источника в графе с неотрицательными ребрами (почему?)
Мы создаем 2 массива: посещенные и удаленные, которые фиксируют, посещена ли вершина и каково минимальное расстояние от исходной вершины соответственно. Первоначально посещаемый массив присваивается как ложный и дальний как бесконечный.
Мы начинаем с исходной вершины. Пусть текущая вершина равна u, а ее смежные вершины - v. Теперь для каждого v, смежного с u, расстояние обновляется, если оно не было посещено раньше, а расстояние от u меньше его текущего расстояния. Затем мы выбираем следующую вершину с наименьшим расстоянием и которая не была посещена.
Приоритетная очередь часто используется для удовлетворения этого последнего требования за минимальное время. Ниже приведена реализация одной и той же идеи с использованием очереди приоритетов в Java.
```java
import java.util.*;
public class Dijkstra {
class Graph {
LinkedList<Pair<Integer>> adj[];
int n; // Number of vertices.
Graph(int n) {
this.n = n;
adj = new LinkedList[n];
for(int i = 0;i<n;i++) adj[i] = new LinkedList<>();
}
// add a directed edge between vertices a and b with cost as weight
public void addEdgeDirected(int a, int b, int cost) {
adj[a].add(new Pair(b, cost));
}
public void addEdgeUndirected(int a, int b, int cost) {
addEdgeDirected(a, b, cost);
addEdgeDirected(b, a, cost);
}
}
class Pair<E> {
E first;
E second;
Pair(E f, E s) {
first = f;
second = s;
}
}
// Comparator to sort Pairs in Priority Queue
class PairComparator implements Comparator<Pair<Integer>> {
public int compare(Pair<Integer> a, Pair<Integer> b) {
return a.second - b.second;
}
}
// Calculates shortest path to each vertex from source and returns the distance
public int[] dijkstra(Graph g, int src) {
int distance[] = new int[gn]; // shortest distance of each vertex from src
boolean visited[] = new boolean[gn]; // vertex is visited or not
Arrays.fill(distance, Integer.MAX_VALUE);
Arrays.fill(visited, false);
PriorityQueue<Pair<Integer>> pq = new PriorityQueue<>(100, new PairComparator());
pq.add(new Pair<Integer>(src, 0));
distance[src] = 0;
while(!pq.isEmpty()) {
Pair<Integer> x = pq.remove(); // Extract vertex with shortest distance from src
int u = x.first;
visited[u] = true;
Iterator<Pair<Integer>> iter = g.adj[u].listIterator();
// Iterate over neighbours of u and update their distances
while(iter.hasNext()) {
Pair<Integer> y = iter.next();
int v = y.first;
int weight = y.second;
// Check if vertex v is not visited
// If new path through u offers less cost then update distance array and add to pq
if(!visited[v] && distance[u]+weight<distance[v]) {
distance[v] = distance[u]+weight;
pq.add(new Pair(v, distance[v]));
}
}
}
return distance;
}
public static void main(String args[]) {
Dijkstra d = new Dijkstra();
Dijkstra.Graph g = d.new Graph(4);
g.addEdgeUndirected(0, 1, 2);
g.addEdgeUndirected(1, 2, 1);
g.addEdgeUndirected(0, 3, 6);
g.addEdgeUndirected(2, 3, 1);
g.addEdgeUndirected(1, 3, 3);
int dist[] = d.dijkstra(g, 0);
System.out.println(Arrays.toString(dist));
}
}
```

View File

@@ -0,0 +1,48 @@
---
title: Floyd Warshall Algorithm
localeTitle: Алгоритм Флойда Варшалла
---
## Алгоритм Флойда Варшалла
Алгоритм Флойда Варшалла - отличный алгоритм для нахождения кратчайшего расстояния между всеми вершинами в графе. Он имеет очень сжатый алгоритм и временную сложность O (V ^ 3) (где V - число вершин). Его можно использовать с отрицательными весами, хотя отрицательные весовые циклы не должны присутствовать на графике.
### оценка
Космическая сложность: O (V ^ 2)
Хуже того, сложность времени: O (V ^ 3)
### Реализация Python
```python
# A large value as infinity
inf = 1e10
def floyd_warshall(weights):
V = len(weights)
distance_matrix = weights
for k in range(V):
next_distance_matrix = [list(row) for row in distance_matrix] # make a copy of distance matrix
for i in range(V):
for j in range(V):
# Choose if the k vertex can work as a path with shorter distance
next_distance_matrix[i][j] = min(distance_matrix[i][j], distance_matrix[i][k] + distance_matrix[k][j])
distance_matrix = next_distance_matrix # update
return distance_matrix
# A graph represented as Adjacency matrix
graph = [
[0, inf, inf, -3],
[inf, 0, inf, 8],
[inf, 4, 0, -2],
[5, inf, 3, 0]
]
print(floyd_warshall(graph))
```
#### Дополнительная информация:
[диаграммы](https://github.com/freecodecamp/guides/computer-science/data-structures/graphs/index.md)
[Флойд Варшалл - Википедия](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)

View File

@@ -0,0 +1,23 @@
---
title: Graph algorithms
localeTitle: Графические алгоритмы
---
## Графические алгоритмы
Графовые алгоритмы представляют собой набор инструкций, которые пересекают (посещает узлы a) графа.
Некоторые алгоритмы используются для поиска определенного узла или пути между двумя заданными узлами.
### Почему алгоритмы графа важны
Графики - очень полезные структуры данных, которые могут быть для моделирования различных проблем. Эти алгоритмы имеют прямые приложения на сайтах Social Networking, State Machine и многие другие.
### Некоторые общие алгоритмы графа
Некоторые из наиболее распространенных алгоритмов графа:
[диаграммы](https://github.com/freecodecamp/guides/computer-science/data-structures/graphs/index.md)
[Первый поиск Breadth (BFS)](https://github.com/freecodecamp/guides/tree/master/src/pages/algorithms/graph-algorithms/breadth-first-search/index.md)
[Глубина первого поиска (DFS)](https://github.com/freecodecamp/guides/tree/master/src/pages/algorithms/graph-algorithms/depth-first-search/index.md)

View File

@@ -0,0 +1,11 @@
---
title: Greatest Common Divisor Direct Analysis
localeTitle: Самый большой общий делитель прямого анализа
---
## Самый большой общий делитель прямого анализа
Это заглушка. [Помогите нашему сообществу расширить его](https://github.com/freecodecamp/guides/tree/master/src/pages/algorithms/greatest-common-divisor-direct-analysis/index.md) .
[Это руководство по быстрому стилю поможет вам принять ваш запрос на тягу](https://github.com/freecodecamp/guides/blob/master/README.md) .
#### Дополнительная информация:

View File

@@ -0,0 +1,75 @@
---
title: Greatest Common Divisor Euclidean
localeTitle: Величайший общий делитель Евклидов
---
## Величайший общий делитель Евклидов
Для этой темы вы должны сначала знать о Величайшем общем делителе (GCD) и операции MOD.
#### Самый большой общий делитель (GCD)
GCD двух или более целых чисел является наибольшим целым числом, которое делит каждое из целых чисел таким образом, что их остаток равен нулю.
Пример-
GCD 20, 30 = 10 _(10 - наибольшее число, которое делит 20 и 30 с остатком в 0)_
GCD 42, 120, 285 = 3 _(3 - наибольшее число, которое делит 42, 120 и 285 с остатком как 0)_
#### Операция "mod"
Операция mod дает вам остаток, когда разделяются два положительных целых числа. Мы пишем его следующим образом:
`A mod B = R`
Это означает, что деление A на B дает вам остаток R, это отличается от операции деления, которая дает вам коэффициент.
Пример-
7 mod 2 = 1 _(Разделение 7 на 2 дает остаток 1)_
42 mod 7 = 0 _(Разделение 42 на 7 дает остаток 0)_
С учетом этих двух понятий вы легко поймете Евклидовы алгоритмы.
### Евклидовой алгоритм для наибольшего общего делителя (GCD)
В евклидовом алгоритме найден GCD из 2 чисел.
Вы лучше поймете этот алгоритм, увидев его в действии. Предполагая, что вы хотите вычислить GCD 1220 и 516, давайте применим Евклидовой алгоритм-
Предполагая, что вы хотите вычислить GCD 1220 и 516, давайте применим Евклидовой алгоритм- ![Пример Евклида](https://i.imgur.com/aa8oGgP.png)
Псевдокод алгоритма-
Шаг 1: **Пусть `a, b` - два числа**
Шаг 2: **`a mod b = R`**
Шаг 3: **Пусть `a = b` и `b = R`**
Шаг 4: **Повторите шаги 2 и 3 до тех пор, пока `a mod b` станет больше 0**
Шаг 5: **GCD = b**
Шаг 6: Закончите
Код Javascript для выполнения GCD-
```javascript
function gcd(a, b) {
var R;
while ((a % b) > 0) {
R = a % b;
a = b;
b = R;
}
return b;
}
```
Код Javascript для выполнения GCD с использованием рекурсивно-
```javascript
function gcd(a, b) {
if (b == 0)
return a;
else
return gcd(b, (a % b));
}
```
Вы также можете использовать Евклидовой алгоритм для поиска GCD более двух чисел. Поскольку GCD ассоциативен, справедлива следующая операция: `GCD(a,b,c) == GCD(GCD(a,b), c)`
Вычислите GCD первых двух чисел, затем найдите GCD результата и следующее число. Пример - `GCD(203,91,77) == GCD(GCD(203,91),77) == GCD(7, 77) == 7`
Вы можете найти GCD из `n` чисел таким же образом.

View File

@@ -0,0 +1,89 @@
---
title: Greedy Algorithms
localeTitle: Жадные алгоритмы
---
## Что такое жадный алгоритм
Вы, должно быть, слышали о многих алгоритмических методах проектирования, просеивая некоторые из статей здесь. Некоторые из них :
* Грубая сила
* Разделить и покорить
* Жадное программирование
* Динамическое программирование назвать несколько. В этой статье вы узнаете, что такое жадный алгоритм и как вы можете использовать эту технику для решения многих проблем программирования, которые в противном случае не кажутся тривиальными.
Представьте, что вы собираетесь отправиться в поход, и ваша цель - достичь максимально возможного пика. У вас уже есть карта, прежде чем вы начнете, но есть тысячи возможных путей, отображаемых на карте. Вы слишком ленивы и просто не имеете времени оценить каждую из них. Вверните карту! Вы начали поход с простой стратегией - быть жадным и близоруким. Просто пройдите по дорожкам, которые больше склоняются вверх. Это похоже на хорошую стратегию для пеших прогулок. Но всегда ли это лучше?
После того, как поездка закончилась, и ваше тело болело и устало, вы впервые смотрите на карту походов. О мой Бог! Там мутная река, которую я должен был пересечь, вместо того, чтобы идти вверх. Это означает, что жадный алгоритм выбирает лучший немедленный выбор и никогда не пересматривает свой выбор. Что касается оптимизации решения, это просто означает, что жадное решение будет пытаться найти локальные оптимальные решения, которые могут быть многими, и могут пропустить глобальное оптимальное решение.
## Формальное определение
Предположим, что у вас есть целевая функция, которая должна быть оптимизирована (максимизирована или минимизирована) в данной точке. Алгоритм Greedy делает жадные варианты на каждом шаге, чтобы оптимизировать целевую функцию. Алгоритм Жадности имеет только один выстрел для вычисления оптимального решения, чтобы он никогда не возвращался и не менял решение.
### Жадные алгоритмы имеют некоторые преимущества и недостатки:
* Легко придумать жадный алгоритм (или даже несколько жадных алгоритмов) для проблемы. Анализ времени выполнения жадных алгоритмов будет намного проще, чем для других методов (например, Divide and conquer). Для техники «Разделить и властвовать» неясно, является ли техника быстрой или медленной. Это связано с тем, что на каждом уровне рекурсии размер уменьшается и увеличивается количество подзадач.
* Трудная часть заключается в том, что для жадных алгоритмов вам приходится много работать, чтобы понять проблемы правильности. Даже при правильном алгоритме трудно доказать, почему оно правильно. Доказательство правильности жадного алгоритма - это скорее искусство, чем наука. Это связано с большим количеством творчества. Обычно придумывание алгоритма может показаться тривиальным, но доказывая, что оно на самом деле правильно, представляет собой совершенно другую проблему.
## Проблема с интервальным расписанием
Давайте погрузиться в интересную проблему, с которой вы можете столкнуться практически в любой отрасли или в любом обществе. Некоторые примеры проблемы заключаются в следующем:
* В течение одного дня в университете вам предоставляется набор N графиков лекций. График для конкретной лекции имеет вид ( ремя,_ время), где ремя представляет собой время начала этой лекции, и аналогично время f_ представляет время окончания. Учитывая список N расписаний лекций, нам нужно выбрать максимальный набор лекций, которые будут проводиться в течение дня, чтобы **ни одна из лекций не совпадала одна с другой, т.е. если лекция Li и Lj включены в наш выбор, тогда время начала j > = время окончания i или наоборот** .
* Ваш друг работает в качестве советника лагеря, и он отвечает за организацию мероприятий для набора отдыхающих. Один из его планов состоит в следующем упражнении по мини-триатлону: каждый участник должен поплавать 20 кругов пула, затем проехать 10 миль, затем пробежать 3 мили.
* План состоит в том, чтобы отправить участников в шахматном порядке по следующему правилу: участники должны использовать пул по одному за раз. Другими словами, первый участник соревнований плавает по 20 кругов, выходит и начинает кататься на велосипеде.
* Как только этот первый человек выходит из бассейна, второй участник начинает плавать 20 кругов; как только он или она выходит и начинает кататься на велосипеде, третий участник начинает плавать и так далее.
* Каждый участник имеет запланированное время плавания, прогнозируемое время езды на велосипеде и прогнозируемое время работы. Ваш друг хочет принять решение о расписании для триатлона: порядок, в котором можно начинать старты конкурсантов.
* Предположим, что время завершения расписания - это самое раннее время, когда все участники будут закончены со всеми тремя ногами триатлона, предполагая, что прогнозы времени точны. Каков наилучший порядок отправки людей, если вы хотите, чтобы весь конкурс закончился как можно скорее? Точнее, дать эффективный алгоритм, который создает график, время завершения которого как можно меньше
### Проблема планирования лекций
Давайте рассмотрим различные подходы к решению этой проблемы.
1. **Самое раннее время начала Сначала** выберите интервал, который имеет самое раннее время начала. Взгляните на следующий пример, который нарушает это решение. Это решение не получилось, потому что может быть интервал, который начинается очень рано, но очень длинный. Это означает, что следующая стратегия, которую мы могли бы попробовать, будет заключаться в том, чтобы сначала посмотреть на меньшие интервалы. ![Самое раннее время начала](https://algorithmsandme.files.wordpress.com/2015/03/f268b-jobs.png?w=840)
2. **Наименьший интервал Первый,** т. Е. Вы в конечном итоге выбираете лекции в порядке их общего интервала, который является ничем иным, как их `finish time - start time` . Опять же, это решение неверно. Посмотрите на следующий случай. ![Кратчайший интервал](https://i.stack.imgur.com/4bz2N.png)
Вы можете отчетливо видеть, что кратчайшая лекция - это посередине, но здесь это не оптимальное решение. Давайте посмотрим на еще одно решение этой проблемы, получающее информацию из этого решения.
3. **Наименее конфликтный интервал Сначала** вы должны смотреть на интервалы, которые вызывают наименьшее количество конфликтов. Еще раз у нас есть пример, когда этот подход не находит оптимального решения. ![Наименее конфликтный интервал](https://i.stack.imgur.com/5LZ9V.png)
Диаграмма показывает нам, что наименьший интервал согласования - это один посередине с двумя конфликтами. После этого мы можем выбрать только два интервала в самом конце с конфликтами 3 каждый. Но оптимальным решением является выбор 4 интервалов на самом верхнем уровне.
4. **Самое раннее время окончания** . Это тот подход, который всегда дает нам наиболее оптимальное решение этой проблемы. Мы получили много идей из предыдущих подходов и, наконец, пришли к такому подходу. Мы сортируем интервалы в соответствии с возрастающим порядком их времени окончания, а затем начинаем выбирать интервалы с самого начала. Посмотрите на следующий псевдо-код для большей ясности.
```
function interval_scheduling_problem(requests)
schedule \gets \{\}
while requests is not yet empty
choose a request i_r \in requests that has the lowest finishing time
schedule \gets schedule \cup \{i_r\}
delete all requests in requests that are not compatible with i_r
end
return schedule
end
```
## Когда мы используем Жадные алгоритмы
Жадные алгоритмы могут помочь вам найти решения многих, казалось бы, сложных проблем. Единственная проблема с ними заключается в том, что вы можете найти правильное решение, но вы, возможно, не сможете проверить, соответствует ли он правильному. Все жадные проблемы разделяют общее свойство, что локальный оптимизатор может в конечном итоге привести к глобальным минимумам, не пересматривая уже принятый набор вариантов.
Жадные алгоритмы помогают нам решать множество различных проблем. Будьте в курсе предстоящих учебников по каждому из них.
1. Кратчайший путь.
2. Минимальная проблема связующего дерева на графике.
3. Проблема кодирования Хаффмана.
4. Проблема K-центров
#### Дополнительная информация:
[![Жадные проблемы](http://img.youtube.com/vi/HzeK7g8cD0Y/0.jpg)](https://www.youtube.com/watch?v=HzeK7g8cD0Y)
[![Жадные проблемы](http://img.youtube.com/vi/poWB2UCuozA/0.jpg)](https://www.youtube.com/watch?v=poWB2UCuozA)

View File

@@ -0,0 +1,53 @@
---
title: Algorithms
localeTitle: Алгоритмы
---
## Алгоритмы
В информатике алгоритм является однозначной спецификацией того, как решить класс проблем. Алгоритмы могут выполнять вычисления, обработку данных и автоматизированные задачи рассуждения.
Алгоритм - эффективный метод, который может быть выражен в конечном объеме пространства и времени и в определенном формальном языке для вычисления функции. Исходя из начального состояния и начального ввода (возможно, пустого), инструкции описывают вычисление, которое при его выполнении проходит через конечное число четко определенных последовательных состояний, в конечном итоге создавая «выход» и заканчивая в конечном конечном состоянии. Переход от одного состояния к другому не обязательно детерминирован; некоторые алгоритмы, известные как рандомизированные алгоритмы, включают случайный ввод.
Существуют определенные требования, которым должен следовать алгоритм:
1. Определенность: каждый шаг в этом процессе точно определен.
2. Эффективная вычислимость: каждый шаг процесса может выполняться компьютером.
3. Конечность: программа в конечном итоге успешно завершится.
Некоторые распространенные типы алгоритмов включают алгоритмы сортировки, алгоритмы поиска и алгоритмы сжатия. Классы алгоритмов включают Graph, Dynamic Programming, Sorting, Search, Strings, Math, Computational Geometry, Optimization и Miscellaneous. Хотя технически это не класс алгоритмов, структуры данных часто группируются вместе с ними.
### КПД
Алгоритмы чаще всего оцениваются по их эффективности и количеству вычислительных ресурсов, которые они требуют для выполнения своей задачи. Общим способом оценки алгоритма является рассмотрение его временной сложности. Это показывает, как время работы алгоритма растет с увеличением размера ввода. Поскольку сегодня алгоритмы должны работать на больших входах данных, для наших алгоритмов очень важно иметь достаточно быстрое время работы.
### Алгоритмы сортировки
Алгоритмы сортировки бывают разных вкусов в зависимости от вашей необходимости. Некоторые, очень распространенные и широко используемые:
#### Быстрая сортировка
Нет сортировки, которая может закончиться без быстрого сортировки. Основная концепция приведена в ссылке ниже. [Быстрая сортировка](http://me.dt.in.th/page/Quicksort/)
#### Сортировка слиянием
Это алгоритм сортировки, который опирается на понятие, как сортировать массивы объединяются, чтобы дать один отсортированный массивы. Об этом подробнее здесь- [Сортировка слиянием](https://www.geeksforgeeks.org/merge-sort/)
Учебная программа freeCodeCamp сильно подчеркивает создание алгоритмов. Это потому, что алгоритмы обучения - это хороший способ практиковать навыки программирования. Интервьюеры чаще всего тестируют кандидатов по алгоритмам во время собеседований на собеседовании разработчиков.
### Дополнительные ресурсы
[Введение в алгоритмы | Краш-курс: информатика](https://www.youtube.com/watch?v=rL8X2mlNHPM)
Это видео дает доступное и живое введение в алгоритмы, ориентированные на алгоритмы сортировки и поиска по графику.
[Что такое Алгоритм и почему вы должны заботиться? | Ханская академия](https://www.youtube.com/watch?v=CvSOaYi89B4)
В этом видео представлены алгоритмы и кратко обсуждается их использование в больших профилях.
[15 алгоритмов сортировки за 6 минут | Тимо Бинманн](https://www.youtube.com/watch?v=kPRA0W1kECg)
Это видео визуально демонстрирует некоторые популярные алгоритмы сортировки, которые обычно преподают в курсах программирования и компьютерных наук.
[Алгоритм визуализатора](http://algo-visualizer.jasonpark.me)
Это также очень хороший проект с открытым исходным кодом, который помогает вам визуализировать алгоритмы.

View File

@@ -0,0 +1,61 @@
---
title: Lee's Algorithm
localeTitle: Алгоритм Ли
---
## Алгоритм Ли
Алгоритм Ли является одним из возможных решений для задач маршрутизации лабиринта. Он всегда дает оптимальное решение, если оно существует, но оно медленный и требует большой памяти для плотной компоновки.
### Понимание того, как это работает
Алгоритм представляет собой алгоритм на основе `breadth-first` который использует `queues` для хранения шагов. Он обычно использует следующие шаги:
1. Выберите начальную точку и добавьте ее в очередь.
2. Добавьте действительные соседние ячейки в очередь.
3. Удалите позицию, в которой вы находитесь, и переходите к следующему элементу.
4. Повторяйте шаги 2 и 3, пока очередь не будет пустой.
### Реализация
C ++ имеет очередь, уже реализованную в библиотеке `<queue>` , но если вы используете что-то еще, вы можете реализовать ваша собственная версия очереди.
Код C ++:
```c++
int dl[] = {-1, 0, 1, 0}; // these arrays will help you travel in the 4 directions more easily
int dc[] = {0, 1, 0, -1};
queue<int> X, Y; // the queues used to get the positions in the matrix
X.push(start_x); //initialize the queues with the start position
Y.push(start_y);
void lee()
{
int x, y, xx, yy;
while(!X.empty()) // while there are still positions in the queue
{
x = X.front(); // set the current position
y = Y.front();
for(int i = 0; i < 4; i++)
{
xx = x + dl[i]; // travel in an adiacent cell from the current position
yy = y + dc[i];
if('position is valid') //here you should insert whatever conditions should apply for your position (xx, yy)
{
X.push(xx); // add the position to the queue
Y.push(yy);
mat[xx][yy] = -1; // you usually mark that you have been to this position in the matrix
}
}
X.pop(); // eliminate the first position, as you have no more use for it
Y.pop();
}
}
```

View File

@@ -0,0 +1,37 @@
---
title: Red Black Trees
localeTitle: Красные Черные Деревья
---
## Красные Черные Деревья
Red-Black Tree - это самобалансирующееся двоичное дерево поиска (BST), где каждый узел следует следующим правилам.
1. У каждого узла есть двое детей, окрашенных либо красным, либо черным.
2. Каждый узел дерева листьев всегда черный.
3. Каждый красный узел имеет обоих своих детей, окрашенных в черный цвет.
4. Нет двух соседних красных узлов (красный узел не может иметь красный родительский или красный ребенок).
5. Каждый путь от корня до узла дерева имеет одинаковое количество черных узлов (называемое «черной высотой»).
Референс-стиль: ![alt text](https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/Fibonacci_Tree_as_Red-Black_Tree.svg/2000px-Fibonacci_Tree_as_Red-Black_Tree.svg.png "Пример фибоначчи из красных черных деревьев")
### Почему красно-черные деревья?
Большинство операций BST (например, поиск, макс, мин, вставка, удаление и т. Д.) Принимают O (h) время, где h - высота BST. Стоимость этих операций может стать O (n) для искаженного двоичного дерева. Если мы уверены, что высота дерева остается O (Logn) после каждой вставки и удаления, мы можем гарантировать верхнюю границу O (Logn) для всех этих операций. Высота красно-черного дерева всегда равна O (Logn), где n - количество узлов в дереве.
### Сравнение с AVL Tree
Деревья AVL более сбалансированы по сравнению с красными черными деревьями, но при вставке и удалении они могут вызывать больше поворотов. Поэтому, если ваше приложение связано с многочисленными частыми вставками и удалениями, то предпочтение следует отдавать от деревьев красного цвета. И если вставки и удаления менее часты, а поиск - более частая операция, тогда дерево AVL должно быть предпочтительнее Red Black Tree.
### Левонападение красно-черного дерева
Дерево с красным-черным деревом (LLRB) с левой стороны является типом самобалансирующегося двоичного дерева поиска. Это вариант красно-черного дерева и гарантирует такую ​​же асимптотическую сложность операций, но его проще реализовать.
### Свойства левых одетых красно-черных деревьев
Все предложенные алгоритмы красно-черного дерева характеризуются наихудшим временем поиска, ограниченным малой константой, кратной log N в дереве из N ключей, а поведение, наблюдаемое на практике, обычно такое же, что и несколько быстрее, чем наихудшая оценка, близкая к рассмотренным оптимальным логарифмическим узлам N, которые наблюдались бы в идеально сбалансированном дереве.
В частности, в левом наклоне красно-черного 2-3 дерева, построенного из N случайных клавиш: -> Случайный успешный поиск исследует log2 N - 0.5 узлов. -> Средняя высота дерева составляет около 2 log2 N
#### Дополнительная информация:
* [Видео из алгоритмов и структур данных](https://www.youtube.com/watch?v=2Ae0D6EXBV4)

View File

@@ -0,0 +1,268 @@
---
title: Binary Search
localeTitle: Двоичный поиск
---
## Двоичный поиск
Двоичный поиск обнаруживает элемент в отсортированном массиве путем многократного деления интервала поиска пополам.
Как искать имя в телефонной книге?
Один из способов - начать с первой страницы и посмотреть на каждое имя в телефонной книге, пока мы не найдем то, что ищем. Но это был бы чрезвычайно трудоемкий и неэффективный способ поиска.
Поскольку мы знаем, что имена в телефонной книге отсортированы в алфавитном порядке, мы, вероятно, могли бы выполнить следующие шаги:
1. Откройте среднюю страницу телефонной книги
2. Если у нас есть имя, которое мы ищем, мы закончили!
3. В противном случае отбросьте половину телефонной книги, которая не содержит имени
4. Повторяйте до тех пор, пока вы не найдете имя или больше страниц осталось в телефонной книге
Сложность времени. Поскольку мы удаляем одну часть случая поиска на каждом этапе бинарного поиска и выполняем операцию поиска в другой половине, это приводит к худшей временной сложности _O_ ( _log 2 N_ ).
Космическая сложность: двоичный поиск принимает постоянное или _O_ ( _1_ ) пространство, что означает, что мы не определяем какую-либо переменную, зависящую от размера ввода.
для небольших наборов линейный поиск лучше, но в более крупных методах более эффективно использовать двоичный поиск.
В деталях, сколько раз вы можете разделить N на 2, пока не получите 1? По сути, это означает, что вы выполняете двоичный поиск (половина элементов), пока не найдете его. В формуле это будет следующим:
```
1 = N / 2x
```
Умножить на 2x:
```
2x = N
```
Теперь сделайте log2:
```
log2(2x) = log2 N
x * log2(2) = log2 N
x * 1 = log2 N
```
Это означает, что вы можете разделить log N раз, пока не разделите все. Это означает, что вам нужно разделить лог N («выполнить шаг двоичного поиска»), пока не найдете свой элемент.
_O_ ( _log 2 N_ ) такова, что на каждом шаге половина элементов в наборе данных ушла, что оправдано основанием логарифмической функции.
Это алгоритм двоичного поиска. Он элегантен и эффективен, но для правильной работы массив должен быть **отсортирован** .
* * *
Найдите 5 в заданном массиве чисел, используя двоичный поиск.
![Двоичный поиск 1](https://i.imgur.com/QAuugOL.jpg)
Отметьте низкие, высокие и средние позиции в массиве.
![Двоичный поиск 2](https://i.imgur.com/1710fEx.jpg)
Сравните элемент, который вы ищете, с помощью среднего элемента.
![Двоичный поиск 3](https://i.imgur.com/jr4icze.jpg)
Выбросьте левую половину и посмотрите в правую половину.
![Двоичный поиск 4](https://i.imgur.com/W57lGsk.jpg)
Снова сравните с средним элементом.
![Двоичный поиск 5](https://i.imgur.com/5Twm8NE.jpg)
Теперь перейдите в левую половину.
![Двоичный поиск 6](https://i.imgur.com/01xetay.jpg)
Средний элемент - это тот элемент, который мы искали!
Алгоритм бинарного поиска использует подход «разделяй и властвуй», где массив непрерывно делится до тех пор, пока элемент не будет найден или пока не останется больше элементов для проверки. Следовательно, этот алгоритм может быть определен рекурсивно для создания элегантного решения.
Два базовых случая для рекурсии:
* В массиве осталось больше элементов
* Элемент найден
Сила двоичного поиска в системах данных (деревья B +): Деревья двоичного поиска очень мощные из-за их времени поиска O (log n), во-вторых, для структуры данных hashmap, которая использует ключ ключа для поиска данных в O (1). Важно понимать, как время выполнения журнала n поступает с высоты двоичного дерева поиска. Если каждый узел разбит на два узла (двоичный), то глубина дерева будет log n (база 2). Чтобы улучшить эту скорость в Data System, мы используем деревья B +, потому что они имеют больший коэффициент ветвления и поэтому больше высота. Я надеюсь, что эта короткая статья поможет вам разобраться в том, как бинарный поиск используется в практических системах.
Код для рекурсивного двоичного поиска показан ниже:
### Реализация Javascript
```javascript
function binarySearch(arr, item, low, high) {
if (low > high) { // No more elements in the array.
return null;
}
// Find the middle of the array.
var mid = Math.ceil((low + high) / 2);
if (arr[mid] === item) { // Found the item!
return mid;
}
if (item < arr[mid]) { // Item is in the half from low to mid-1.
return binarySearch(arr, item, low, mid-1);
}
else { // Item is in the half from mid+1 to high.
return binarySearch(arr, item, mid+1, high);
}
}
var numbers = [1,2,3,4,5,6,7];
print(binarySearch(numbers, 5, 0, numbers.length-1));
```
Вот еще одна реализация в Javascript:
```Javascript
function binary_search(a, v) {
function search(low, high) {
if (low === high) {
return a[low] === v;
} else {
var mid = math_floor((low + high) / 2);
return (v === a[mid])
||
(v < a[mid])
? search(low, mid - 1)
: search(mid + 1, high);
}
}
return search(0, array_length(a) - 1);
}
```
### Реализация Ruby
```ruby
def binary_search(target, array)
sorted_array = array.sort
low = 0
high = (sorted_array.length) - 1
while high >= low
middle = (low + high) / 2
if target > sorted_array[middle]
low = middle + 1
elsif target < sorted_array[middle]
high = middle - 1
else
return middle
end
end
return nil
end
```
### Пример в C
```C
int binarySearch(int a[], int l, int r, int x) {
if (r >= l){
int mid = l + (r - l)/2;
if (a[mid] == x)
return mid;
if (arr[mid] > x)
return binarySearch(arr, l, mid-1, x);
return binarySearch(arr, mid+1, r, x);
}
return -1;
}
```
### Реализация C / C ++
```C++
int binary_search(int arr[], int l, int r, int target)
{
if (r >= l)
{
int mid = l + (r - l)/2;
if (arr[mid] == target)
return mid;
if (arr[mid] > target)
return binary_search(arr, l, mid-1, target);
return binary_search(arr, mid+1, r, target);
}
return -1;
}
```
### Реализация Python
```Python
def binary_search(arr, l, r, target):
if r >= l:
mid = l + (r - l)/2
if arr[mid] == target:
return mid
elif arr[mid] > target:
return binary_search(arr, l, mid-1, target)
else:
return binary_search(arr, mid+1, r, target)
else:
return -1
```
### Пример в C ++
```c++
// Binary Search using iteration
int binary_search(int arr[], int beg, int end, int num)
{
while(beg <= end){
int mid = (beg + end) / 2;
if(arr[mid] == num)
return mid;
else if(arr[mid] < num)
beg = mid + 1;
else
end = mid - 1;
}
return -1;
}
```
```c++
// Binary Search using recursion
int binary_search(int arr[], int beg, int end, int num)
{
if(beg <= end){
int mid = (beg + end) / 2;
if(arr[mid] == num)
return mid;
else if(arr[mid] < num)
return binary_search(arr, mid + 1, end, num);
else
return binary_search(arr, beg, mid - 1, num);
}
return -1;
}
```
### Пример в C ++
Рекурсивный подход!
\`\` \`C ++ - Рекурсивный подход int binarySearch (int arr \[\], int start, int end, int x) { if (end> = start) { int mid = start + (end-start) / 2; if (arr \[mid\] == x)
возвращение в середине;
```
if (arr[mid] > x)
return binarySearch(arr, start, mid-1, x);
return binarySearch(arr, mid+1, end, x);
```
} return -1; }
```
Iterative approach!
```
C ++ - Итеративный подход int binarySearch (int arr \[\], int start, int end, int x) { while (start <= end) { int mid = start + (end-start) / 2; if (arr \[mid\] == x) возвращение в середине; if (arr \[mid\] <x) start = mid + 1; еще end = mid - 1; } return -1; } \`\` \`
### Больше информации
* [Бинарный поиск (видео на YouTube)](https://youtu.be/P3YID7liBug)
* [Двоичный поиск - CS50](https://www.youtube.com/watch?v=5xlIPT1FRcA)

View File

@@ -0,0 +1,95 @@
---
title: Exponential Search
localeTitle: Экспоненциальный поиск
---
## Экспоненциальный поиск
Экспоненциальный поиск также известен как поиск пальцем, поиск элемента в отсортированном массиве путем прыжка `2^i` элементов на каждой итерации, где i представляет значение переменной управления циклом, а затем проверку наличия элемента поиска между последним прыжком и текущим прыжком
# Сложность Худший случай
O (журнал (N)) Часто путают из-за имени, алгоритм называется так не из-за временной сложности. Имя возникает из-за алгоритма, прыгающего с шагами, равными показателям 2
# Работает
1. `Array[2^(i-1)] < valueWanted < Array[2^i]` элементы массива `2^i` за раз, ища условие. `Array[2^(i-1)] < valueWanted < Array[2^i]` . Если `2^i` больше длины массива, установите верхнюю границу длины массива.
2. Сделайте двоичный поиск между `Array[2^(i-1)]` и `Array[2^i]`
# Код
```
// C++ program to find an element x in a
// sorted array using Exponential search.
#include <bits/stdc++.h>
using namespace std;
int binarySearch(int arr[], int, int, int);
// Returns position of first ocurrence of
// x in array
int exponentialSearch(int arr[], int n, int x)
{
// If x is present at firt location itself
if (arr[0] == x)
return 0;
// Find range for binary search by
// repeated doubling
int i = 1;
while (i < n && arr[i] <= x)
i = i*2;
// Call binary search for the found range.
return binarySearch(arr, i/2, min(i, n), x);
}
// A recursive binary search function. It returns
// location of x in given array arr[l..r] is
// present, otherwise -1
int binarySearch(int arr[], int l, int r, int x)
{
if (r >= l)
{
int mid = l + (r - l)/2;
// If the element is present at the middle
// itself
if (arr[mid] == x)
return mid;
// If element is smaller than mid, then it
// can only be present n left subarray
if (arr[mid] > x)
return binarySearch(arr, l, mid-1, x);
// Else the element can only be present
// in right subarray
return binarySearch(arr, mid+1, r, x);
}
// We reach here when element is not present
// in array
return -1;
}
int main(void)
{
int arr[] = {2, 3, 4, 10, 40};
int n = sizeof(arr)/ sizeof(arr[0]);
int x = 10;
int result = exponentialSearch(arr, n, x);
(result == -1)? printf("Element is not present in array")
: printf("Element is present at index %d", result);
return 0;
}
```
# Больше информации
* [Википедия](https://en.wikipedia.org/wiki/Exponential_search)
* [GeeksForGeeks](https://www.geeksforgeeks.org/exponential-search/)
# кредиты
[Реализация C ++](https://www.wikitechy.com/technology/exponential-search/)

View File

@@ -0,0 +1,21 @@
---
title: Search Algorithms
localeTitle: Алгоритмы поиска
---
## Алгоритмы поиска
В информатике алгоритмом поиска является любой алгоритм, который решает проблему поиска, а именно: извлекать информацию, хранящуюся в некоторой структуре данных, или рассчитывать в пространстве поиска проблемного домена. Примеры таких структур включают связанные списки, массивы данных данных, деревья поиска и многое другое. Соответствующий алгоритм поиска часто зависит от поиска данных, но также от предварительного знания данных. [Подробнее о википедии](https://en.wikipedia.org/wiki/Search_algorithm) .
Этот алгоритм рассматривает проблему переустановки массива элементов в порядке ввода. Два наиболее общих примера этого - бинарный поиск и алгоритм сортировки слияния.
В следующих ссылках вы также можете найти дополнительную информацию о:
* Двоичный поиск
* Линейный поиск
* Поиск связанных списков против массивов
#### Дополнительная информация:
* MIT OCW Введение в алгоритмы [поиска](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-01sc-introduction-to-electrical-engineering-and-computer-science-i-spring-2011/unit-4-probability-and-planning/search-algorithms/) .
* Принстонский университет: [сортировка и поиск.](https://introcs.cs.princeton.edu/java/42sort/)
* Анатомия поисковой системы [(Google).](http://infolab.stanford.edu/~backrub/google.html)

View File

@@ -0,0 +1,29 @@
---
title: Jump Search
localeTitle: Перейти к поиску
---
## Перейти к поиску
Поиск по скачкам обнаруживает элемент в отсортированном массиве, перескакивая k itens и затем проверяя, нужен ли элемент между предыдущий прыжок и текущий прыжок.
# Сложность Худший случай
O (√N)
# Работает
1. Определите значение k, число прыжков: оптимальный размер перехода - √N, где N - длина массива
2. Перейдите в массив k-by-k, `Array[i] < valueWanted < Array[i+k]` поиск по условию `Array[i] < valueWanted < Array[i+k]`
3. Сделайте линейный поиск между `Array[i]` и `Array[i + k]`
![Прыжки с поиском 1](https://i1.wp.com/theoryofprogramming.com/wp-content/uploads/2016/11/jump-search-1.jpg?resize=676%2C290)
# Код
Чтобы просмотреть примеры реализации кода этого метода, перейдите по этой ссылке ниже:
[Поиск по прыжкам - OpenGenus / космос](https://github.com/OpenGenus/cosmos/tree/master/code/search/jump_search)
# кредиты
[Изображение массива логики](http://theoryofprogramming.com/2016/11/10/jump-search-algorithm/)

View File

@@ -0,0 +1,140 @@
---
title: Linear Search
localeTitle: Линейный поиск
---
## Линейный поиск
Предположим, вам предоставлен список или массив элементов. Вы ищете определенный предмет. Как ты это делаешь?
Найдите номер 13 в данном списке.
![Линейный поиск 1](https://i.imgur.com/ThkzYEV.jpg)
Вы просто смотрите на список, и вот он!
![Линейный поиск 2](https://i.imgur.com/K7HfCly.jpg)
Теперь, как вы говорите компьютеру, чтобы его найти.
Компьютер не может смотреть больше, чем значение в данный момент времени. Поэтому он берет один элемент из массива и проверяет, совпадает ли он с тем, что вы ищете.
![Линейный поиск 3](https://i.imgur.com/ZOSxeZD.jpg)
Первый элемент не совпал. Поэтому переходите к следующему.
![Линейный поиск 4](https://i.imgur.com/SwKsPxD.jpg)
И так далее…
Это делается до тех пор, пока не будет найдено совпадение или пока все элементы не будут проверены.
![Линейный поиск 5](https://i.imgur.com/3AaViff.jpg)
В этом алгоритме вы можете остановиться, когда элемент найден, и тогда нет необходимости смотреть дальше.
Итак, сколько времени потребуется на операцию линейного поиска? В лучшем случае вам может повезти, и предмет, на который вы смотрите, может быть, на первой позиции в массиве! Но в худшем случае вам придется смотреть на каждый элемент, прежде чем вы найдете элемент на последнем месте или до того, как осознаете, что элемент не находится в массиве.
Поэтому сложность линейного поиска заключается в следующем: O (n).
Если элемент, подлежащий поиску, возглавляет первый блок памяти, тогда сложность будет: O (1).
Код для функции линейного поиска в JavaScript показан ниже. Эта функция возвращает позицию элемента, который мы ищем в массиве. Если элемент отсутствует в массиве, функция возвращает null.
### Пример в Javascript
```javascript
function linearSearch(arr, item) {
// Go through all the elements of arr to look for item.
for (var i = 0; i < arr.length; i++) {
if (arr[i] === item) { // Found it!
return i;
}
}
// Item not found in the array.
return null;
}
```
### Пример в Ruby
```ruby
def linear_search(target, array)
counter = 0
while counter < array.length
if array[counter] == target
return counter
else
counter += 1
end
end
return nil
end
```
### Пример в C ++
```c++
int linear_search(int arr[],int n,int num)
{
for(int i=0;i<n;i++){
if(arr[i]==num)
return i;
}
// Item not found in the array
return -1;
}
```
### Пример в Python
```python
def linear_search(array, num):
for i in range(len(array)):
if (array[i]==num):
return i
return -1
```
## Глобальный линейный поиск
Что делать, если вы ищете несколько вхождений элемента? Например, вы хотите увидеть, сколько 5 в массиве.
Цель = 5
Массив = \[1, 2, 3, 4, 5, 6, 5, 7, 8, 9, 5\]
Этот массив имеет 3 входа 5s, и мы хотим вернуть индексы (где они находятся в массиве) всех из них. Это называется глобальным линейным поиском, и вам нужно будет настроить свой код, чтобы вернуть массив указательных точек, в которых он обнаруживает целевой элемент. Когда вы найдете элемент индекса, который соответствует вашей цели, в массиве результатов будет добавлена ​​точка-указатель (счетчик). Если он не соответствует коду, он продолжит движение к следующему элементу массива, добавив 1 к счетчику.
```ruby
def global_linear_search(target, array)
counter = 0
results = []
while counter < array.length
if array[counter] == target
results << counter
counter += 1
else
counter += 1
end
end
if results.empty?
return nil
else
return results
end
end
```
## Почему линейный поиск неэффективен
Нет никаких сомнений в том, что линейный поиск прост, но поскольку он сравнивает каждый элемент один за другим, он занимает много времени и, следовательно, не очень эффективен. Если нам нужно найти число, скажем, 1000000 номеров и номеров находится в последнем месте, техника линейного поиска станет довольно утомительной. Итак, также узнайте о сортировке пузырьков, быстрой сортировке и т. Д.
#### Соответствующее видео:
#### Другие источники
[Линейный поиск - CS50](https://www.youtube.com/watch?v=vZWfKBdSgXI)

View File

@@ -0,0 +1,23 @@
---
title: Searching Linked Lists Versus Arrays
localeTitle: Поиск связанных списков в сравнении с массивами
---
## Поиск связанных списков в сравнении с массивами
Предположим, вам нужно искать элемент в есортированном_ связанном списке и массиве. В этом случае вам необходимо выполнить линейный поиск (помните, unsorted). Выполнение линейного поиска элемента в любой структуре данных будет выполнять операцию O (n).
Теперь, если у вас есть _отсортированный_ связанный список и массив, вы можете искать в обеих структурах данных в O (log n) время с помощью Binary Search. Хотя, будет немного утомительно кодировать при использовании связанных списков.
Связанные списки обычно предпочтительны для массивов, где вставка является частой операцией. Его легче вставлять в связанные списки, поскольку изменяется только указатель. Но чтобы вставить в массив (средний или начальный), вам нужно переместить все элементы после того, который вы вставляете. Другое место, где вы должны использовать связанные списки, - это размер неопределенности (вы не знаете размер, когда вы начинаете), потому что массивы имеют фиксированный размер.
Массивы предоставляют несколько преимуществ по сравнению с связанными списками:
1. Случайный доступ
2. Меньше памяти по сравнению со связанными списками
3. Массивы имеют лучшую локальность кэша, что обеспечивает лучшую производительность
Это полностью зависит от варианта использования для того, лучше ли массивы или связанные списки.
### Дополнительная информация:
* Подход программиста к взгляду на связанный список против массива: [выродки для вундеркиндов](http://www.geeksforgeeks.org/programmers-approach-looking-array-vs-linked-list/)

View File

@@ -0,0 +1,154 @@
---
title: Bubble Sort
localeTitle: Сортировка пузырьков
---
## Сортировка пузырьков
Bubble Sort - это самый простой алгоритм сортировки, который работает путем многократной замены соседних элементов, если они находятся в неправильном порядке.
Это очень медленный алгоритм сортировки по сравнению с такими алгоритмами, как quicksort, с наихудшей сложностью O (n ^ 2). Однако компромисс заключается в том, что сортировка пузырьков - один из самых простых алгоритмов сортировки для реализации с нуля.
### Пример:
#### Первый проход:
(5 1 4 2 8) -> (1 5 4 2 8). Здесь алгоритм сравнивает первые два элемента и свопы с 5> 1.
(1 5 4 2 8) -> (1 4 5 2 8), своп с 5> 4
(1 4 5 2 8) -> (1 4 2 5 8), своп с 5> 2
(1 4 2 5 8) -> (1 4 2 5 8). Теперь, поскольку эти элементы уже в порядке (8> 5), алгоритм их не заменяет.
#### Второй проход:
(1 4 2 5 8) -> (1 4 2 5 8)
(1 4 2 5 8) -> (1 2 4 5 8), своп с 4> 2
(1 2 4 5 8) -> (1 2 4 5 8)
(1 2 4 5 8) -> (1 2 4 5 8)
Теперь массив уже отсортирован, но наш алгоритм не знает, завершен ли он. Алгоритму нужен один полный проход без обмена, чтобы знать, что он отсортирован.
#### Третий проход:
(1 2 4 5 8) -> (1 2 4 5 8)
(1 2 4 5 8) -> (1 2 4 5 8)
(1 2 4 5 8) -> (1 2 4 5 8)
(1 2 4 5 8) -> (1 2 4 5 8)
#### свойства
* Сложность пространства: O (1)
* Лучшая производительность: O (n)
* Средняя производительность: O (n \* n)
* Наихудшая производительность: O (n \* n)
* Стабильный: Да
### Объяснение видео
[Пузырь сортировать легко](https://www.youtube.com/watch?v=Jdtq5uKz-w4)
Этот код будет использовать сортировку пузырьков для сортировки массива.
```js
let arr = [1, 4, 7, 45, 7,43, 44, 25, 6, 4, 6, 9];
let sorted = false
while(!sorted) {
sorted = true
for(var i=0; i < arr.length; i++) {
if(arr[i] < arr[i-1]) {
let temp = arr[i];
arr[i] = arr[i-1];
arr[i-1] = temp;
sorted = false;
}
}
}
```
### Свойства:
* Космическая сложность: O (1)
* Сложность времени: O (n), O (n \* n), O (n \* n) для наилучших, средних и худших случаев соответственно.
* На месте: Да
* Стабильный: Да
\======= Вот алгоритм, написанный на Java.
```java
public class bubble-sort {
static void sort(int[] arr) {
int n = arr.length;
int temp = 0;
for(int i=0; i < n; i++){
for(int x=1; x < (ni); x++){
if(arr[x-1] > arr[x]){
temp = arr[x-1];
arr[x-1] = arr[x];
arr[x] = temp;
}
}
}
}
public static void main(String[] args) {
for(int i=0; i < 15; i++){
int arr[i] = (int)(Math.random() * 100 + 1);
}
System.out.println("array before sorting\n");
for(int i=0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
bubbleSort(arr);
System.out.println("\n array after sorting\n");
for(int i=0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
}
}
```
\=======
### Рекурсивная реализация Bubble Sort.
```c++
void bubblesort(int arr[], int n)
{
if(n==1) //Initial Case
return;
for(int i=0;i<n-1;i++) //After this pass the largest element will move to its desired location.
{
if(arr[i]>arr[i+1])
{
temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
bubblesort(arr,n-1); //Recursion for remaining array
}
```
### Больше информации
* [Википедия](https://en.wikipedia.org/wiki/Bubble_sort)
* [Алгоритм сортировки пузырьков - CS50](https://youtu.be/Ui97-_n5xjo)
* [Алгоритм сортировки пузырьков - GeeksForGeeks (статья)](http://www.geeksforgeeks.org/bubble-sort)
* [Алгоритм сортировки пузырьков - MyCodeSchool (видео)](https://www.youtube.com/watch?v=Jdtq5uKz-w4)
* [Алгоритмы: Bubble Sort - HackerRank (видео)](https://www.youtube.com/watch?v=6Gv8vg0kcHc)
* [Алгоритм сортировки пузырьков - GeeksForGeeks (видео)](https://www.youtube.com/watch?v=nmhjrI-aW5o)
* [Визуализация сортировки пузырьков](https://www.hackerearth.com/practice/algorithms/sorting/bubble-sort/visualize/)

View File

@@ -0,0 +1,46 @@
---
title: Bucket Sort
localeTitle: Сортировать по
---
## Что такое сортировка ковша?
Сортировка ведра - это алгоритм сортировки сортировки, который работает с элементами, деля их на разные ведра, а затем сортируя эти ведра индивидуально. Каждое ведро сортируется индивидуально с использованием отдельного алгоритма сортировки или путем рекурсивного применения алгоритма сортировки ведра. Сортировка ковша в основном полезна, когда вход равномерно распределен по диапазону.
## Предположим, перед ними стоит следующая проблема:
Каждому был задан большой массив чисел с плавающей запятой, равномерно расположенных между нижней и верхней границей. Этот массив теперь должен быть отсортирован. Простым способом решения этой проблемы будет использование другого алгоритма сортировки, такого как сортировка слияния, сортировка кучи или быстрая сортировка. Однако, эти алгоритмы гарантируют наилучшую временную сложность O (NlogN). Однако, используя сортировку ведра, вышеуказанная задача может быть завершена в O (N) времени.
Давайте поближе рассмотрим это.
Подумайте, нужно создать массив списков, т. Е. Ведер. Теперь элементы должны быть вставлены в эти ведра на основе их свойств. Затем каждый из этих ведер можно сортировать индивидуально, используя Sorting Sort.
### Псевдокод для сортировки ковша:
```
void bucketSort(float[] a,int n)
{
for(each floating integer 'x' in n)
{
insert x into bucket[n*x];
}
for(each bucket)
{
sort(bucket);
}
}
```
### Дополнительная информация:
* [Википедия](https://en.wikipedia.org/wiki/Bucket_sort)
* [GeeksForGeeks](http://www.geeksforgeeks.org/bucket-sort-2/)

View File

@@ -0,0 +1,56 @@
---
title: Counting Sort
localeTitle: Подсчет сортировки
---
## Подсчет сортировки
Counting Sort - метод сортировки, основанный на ключах между определенным диапазоном. Он работает, подсчитывая количество объектов, имеющих разные ключевые значения (вид хэширования). Затем выполните некоторую арифметику, чтобы вычислить положение каждого объекта в выходной последовательности.
### Пример:
```
For simplicity, consider the data in the range 0 to 9.
Input data: 1, 4, 1, 2, 7, 5, 2
1) Take a count array to store the count of each unique object.
Index: 0 1 2 3 4 5 6 7 8 9
Count: 0 2 2 0 1 1 0 1 0 0
2) Modify the count array such that each element at each index
stores the sum of previous counts.
Index: 0 1 2 3 4 5 6 7 8 9
Count: 0 2 4 4 5 6 6 7 7 7
The modified count array indicates the position of each object in
the output sequence.
3) Output each object from the input sequence followed by
decreasing its count by 1.
Process the input data: 1, 4, 1, 2, 7, 5, 2. Position of 1 is 2.
Put data 1 at index 2 in output. Decrease count by 1 to place
next data 1 at an index 1 smaller than this index.
```
### Реализация
```js
let numbers = [1, 4, 1, 2, 7, 5, 2];
let count = [];
let i, z = 0;
let max = Math.max(...numbers);
// initialize counter
for (i = 0; i <= max; i++) {
count[i] = 0;
}
for (i=0; i < numbers.length; i++) {
count[numbers[i]]++;
}
for (i = 0; i <= max; i++) {
while (count[i]-- > 0) {
numbers[z++] = i;
}
}
// output sorted array
for (i=0; i < numbers.length; i++) {
console.log(numbers[i]);
}
```

View File

@@ -0,0 +1,133 @@
---
title: Heapsort
localeTitle: Пирамидальная сортировка
---
## Пирамидальная сортировка
Heapsort - эффективный алгоритм сортировки, основанный на использовании кучи max / min. Куча - это древовидная структура данных, которая удовлетворяет свойству кучи - то есть для максимальной кучи, ключ любого узла меньше или равен ключу его родителя (если у него есть родительский элемент). Это свойство можно использовать для доступа к максимальному элементу в куче в времени O (logn) с использованием метода maxHeapify. Мы выполняем эту операцию n раз, каждый раз перемещая максимальный элемент в куче до вершины кучи и извлекаем ее из кучи и сортировать массив. Таким образом, после n итераций мы будем иметь отсортированную версию входного массива. Этот алгоритм работает в O (nlogn) времени и O (1) дополнительное пространство \[O (n), включая пространство, необходимое для хранения входных данных\], поскольку все операции выполняются полностью на месте.
Наихудшим и средним по времени случаем Хэпсорт является O (nlogn). Несмотря на то, что у heapsort есть более худшая сложность, чем quicksort, хорошо реализованная quicksort работает быстрее на практике. Это алгоритм на основе сравнения, поэтому его можно использовать для нечетных наборов данных, поскольку для элементов может быть определено некоторое отношение (свойство кучи).
Реализация на Java приведена ниже:
```java
import java.util.Arrays;
public class Heapsort {
public static void main(String[] args) {
//test array
Integer[] arr = {1, 4, 3, 2, 64, 3, 2, 4, 5, 5, 2, 12, 14, 5, 3, 0, -1};
String[] strarr = {"hope you find this helpful!", "wef", "rg", "q2rq2r", "avs", "erhijer0g", "ewofij", "gwe", "q", "random"};
arr = heapsort(arr);
strarr = heapsort(strarr);
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(strarr));
}
//O(nlogn) TIME, O(1) SPACE, NOT STABLE
public static <E extends Comparable<E>> E[] heapsort(E[] arr){
int heaplength = arr.length;
for(int i = arr.length/2; i>0;i--){
arr = maxheapify(arr, i, heaplength);
}
for(int i=arr.length-1;i>=0;i--){
E max = arr[0];
arr[0] = arr[i];
arr[i] = max;
heaplength--;
arr = maxheapify(arr, 1, heaplength);
}
return arr;
}
//Creates maxheap from array
public static <E extends Comparable<E>> E[] maxheapify(E[] arr, Integer node, Integer heaplength){
Integer left = node*2;
Integer right = node*2+1;
Integer largest = node;
if(left.compareTo(heaplength) <=0 && arr[left-1].compareTo(arr[node-1]) >= 0){
largest = left;
}
if(right.compareTo(heaplength) <= 0 && arr[right-1].compareTo(arr[largest-1]) >= 0){
largest = right;
}
if(largest != node){
E temp = arr[node-1];
arr[node-1] = arr[largest-1];
arr[largest-1] = temp;
maxheapify(arr, largest, heaplength);
}
return arr;
}
}
```
реализация в C ++
```C++
#include <iostream>
using namespace std;
void heapify(int arr[], int n, int i)
{
int largest = i;
int l = 2*i + 1;
int r = 2*i + 2;
if (l < n && arr[l] > arr[largest])
largest = l;
if (r < n && arr[r] > arr[largest])
largest = r;
if (largest != i)
{
swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(int arr[], int n)
{
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
for (int i=n-1; i>=0; i--)
{
swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
void printArray(int arr[], int n)
{
for (int i=0; i<n; ++i)
cout << arr[i] << " ";
cout << "\n";
}
int main()
{
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr)/sizeof(arr[0]);
heapSort(arr, n);
cout << "Sorted array is \n";
printArray(arr, n);
}
```
### Визуализация
* [USFCA](https://www.cs.usfca.edu/~galles/visualization/HeapSort.html)
* [HackerEarth](https://www.hackerearth.com/practice/algorithms/sorting/heap-sort/tutorial/)
#### Дополнительная информация:
* [Википедия](https://en.wikipedia.org/wiki/Quicksort)

View File

@@ -0,0 +1,54 @@
---
title: Sorting Algorithms
localeTitle: Алгоритмы сортировки
---
## Алгоритмы сортировки
Алгоритмы сортировки - это набор инструкций, которые принимают массив или список в качестве ввода и упорядочивают элементы в определенном порядке.
Сорта чаще всего относятся к числу или форме алфавитного (называемого лексикографического) порядка и могут быть в порядке возрастания (AZ, 0-9) или нисходящего (ZA, 9-0).
### Почему алгоритмы сортировки важны
Поскольку сортировка часто может уменьшить сложность проблемы, это важный алгоритм в области компьютерных наук. Эти алгоритмы имеют прямые приложения в алгоритмах поиска, алгоритмах баз данных, методах разделения и захвата, алгоритмах структуры данных и многом другом.
### Некоторые общие алгоритмы сортировки
Некоторые из наиболее распространенных алгоритмов сортировки:
* Выбор Сортировка
* Сортировка пузырьков
* Вставка Сортировка
* Сортировка слиянием
* Быстрая сортировка
* Куча сортировки
* Подсчет сортировки
* Radix Sort
* Сортировать по
### Классификация алгоритма сортировки
Алгоритмы сортировки могут быть классифицированы на основе следующих параметров:
1. Основано на количестве свопов или инверсии Это количество раз, когда алгоритм свопит элементы для сортировки ввода. `Selection Sort` требуется минимальное количество свопов.
2. Основано на количестве сравнений Это число раз, когда алгоритм сравнивает элементы для сортировки ввода. Используя [нотацию Big-O](https://guide.freecodecamp.org/computer-science/notation/big-o-notation/) , приведенные выше примеры алгоритма сортировки требуют, по крайней мере, `O(nlogn)` сравнений в наилучшем случае и сравнения `O(n^2)` в худшем случае для большинства выходов.
3. На основе рекурсии или нерекурсии Некоторые алгоритмы сортировки, такие как `Quick Sort` , используют рекурсивные методы для сортировки ввода. Другие алгоритмы сортировки, такие как `Selection Sort` или `Insertion Sort` , используют нерекурсивные методы. Наконец, некоторые алгоритмы сортировки, такие как `Merge Sort` , используют как рекурсивные, так и нерекурсивные методы для сортировки ввода.
4. Основываясь на стабильности Алгоритмы сортировки считаются `stable` если алгоритм поддерживает относительный порядок элементов с равными ключами. Другими словами, два эквивалентных элемента остаются в том же порядке на отсортированном выходе, что и на входе.
* `Insertion sort` `Merge Sort` `Bubble Sort` стабильны
* `Heap Sort` и `Quick Sort` нестабильны
1. Основываясь на дополнительных требованиях к пространству Говорят, что алгоритмы сортировки находятся на `in place` если им требуется постоянное `O(1)` дополнительное пространство для сортировки.
* `Insertion sort` и `Quick-sort` находятся `in place` своего рода , как мы перемещаем элементы относительно оси поворота и на самом деле не использовать отдельный массив , который не имеет места в сортировках слияния , где размер входа должен быть выделен заранее , чтобы сохранить выход во время Сортировать.
* `Merge Sort` - пример сортировки `out place` поскольку для его операций требуется дополнительное пространство памяти.
### Наилучшая возможная временная сложность для любой сортировки на основе сравнения
Любой алгоритм сортировки, основанный на сравнении, должен производить, по меньшей мере, сравнение nLog2n для сортировки входного массива, а сортировка Heapsort и merge - это асимптотически оптимальные сортировки сортировки. Это можно легко доказать, построив диаграмму дерева desicion.

View File

@@ -0,0 +1,191 @@
---
title: Insertion Sort
localeTitle: Вставка Сортировка
---
## Вставка Сортировка
Сортировка вставки - это самый простой и эффективный алгоритм сортировки для небольшого числа элементов.
### Пример:
В сортировке Insertion вы сравниваете `key` элемент с предыдущими элементами. Если предыдущие элементы больше `key` элемента, вы перемещаете предыдущий элемент в следующую позицию.
Начните с индекса 1 до размера входного массива.
\[8 3 5 1 4 2\]
Шаг 1 :
! [\[8 3 5 1 4 2\]](https://github.com/blulion/freecodecamp-resource/blob/master/insertion_sort/1.png?raw=true)
```
key = 3 //starting from 1st index.
Here `key` will be compared with the previous elements.
In this case, `key` is compared with 8. since 8 > 3, move the element 8
to the next position and insert `key` to the previous position.
Result: [ 3 8 5 1 4 2 ]
```
Шаг 2 :
! [\[3 8 5 1 4 2\]](https://github.com/blulion/freecodecamp-resource/blob/master/insertion_sort/2.png?raw=true)
```
key = 5 //2nd index
8 > 5 //move 8 to 2nd index and insert 5 to the 1st index.
Result: [ 3 5 8 1 4 2 ]
```
Шаг 3 :
! [\[3 5 8 1 4 2\]](https://github.com/blulion/freecodecamp-resource/blob/master/insertion_sort/3.png?raw=true)
```
key = 1 //3rd index
8 > 1 => [ 3 5 1 8 4 2 ]
5 > 1 => [ 3 1 5 8 4 2 ]
3 > 1 => [ 1 3 5 8 4 2 ]
Result: [ 1 3 5 8 4 2 ]
```
Шаг 4:
! [\[1 3 5 8 4 2\]](https://github.com/blulion/freecodecamp-resource/blob/master/insertion_sort/4.png?raw=true)
```
key = 4 //4th index
8 > 4 => [ 1 3 5 4 8 2 ]
5 > 4 => [ 1 3 4 5 8 2 ]
3 > 4 ≠> stop
Result: [ 1 3 4 5 8 2 ]
```
Шаг 5:
! [\[1 3 4 5 8 2\]](https://github.com/blulion/freecodecamp-resource/blob/master/insertion_sort/5.png?raw=true)
```
key = 2 //5th index
8 > 2 => [ 1 3 4 5 2 8 ]
5 > 2 => [ 1 3 4 2 5 8 ]
4 > 2 => [ 1 3 2 4 5 8 ]
3 > 2 => [ 1 2 3 4 5 8 ]
1 > 2 ≠> stop
Result: [1 2 3 4 5 8]
```
! [\[1 2 3 4 5 8\]](https://github.com/blulion/freecodecamp-resource/blob/master/insertion_sort/6.png?raw=true)
Ниже алгоритм немного оптимизирован, чтобы избежать замены `key` элемента на каждой итерации. Здесь `key` элемент будет заменен в конце итерации (шаг).
```Algorithm
InsertionSort(arr[])
for j = 1 to arr.length
key = arr[j]
i = j - 1
while i > 0 and arr[i] > key
arr[i+1] = arr[i]
i = i - 1
arr[i+1] = key
```
Вот детальная реализация в Javascript:
```
function insertion_sort(A) {
var len = array_length(A);
var i = 1;
while (i < len) {
var x = A[i];
var j = i - 1;
while (j >= 0 && A[j] > x) {
A[j + 1] = A[j];
j = j - 1;
}
A[j+1] = x;
i = i + 1;
}
}
```
Быстрая реализация в Swift приведена ниже:
```swift
var array = [8, 3, 5, 1, 4, 2]
func insertionSort(array:inout Array<Int>) -> Array<Int>{
for j in 0..<array.count {
let key = array[j]
var i = j-1
while (i > 0 && array[i] > key){
array[i+1] = array[i]
i = i-1
}
array[i+1] = key
}
return array
}
```
Пример Java приведен ниже:
```
public int[] insertionSort(int[] arr)
for (j = 1; j < arr.length; j++) {
int key = arr[j]
int i = j - 1
while (i > 0 and arr[i] > key) {
arr[i+1] = arr[i]
i -= 1
}
arr[i+1] = key
}
return arr;
```
### inserting сорт в c ....
```C
void insertionSort(int arr[], int n)
{
int i, key, j;
for (i = 1; i < n; i++)
{
key = arr[i];
j = i-1;
while (j >= 0 && arr[j] > key)
{
arr[j+1] = arr[j];
j = j-1;
}
arr[j+1] = key;
}
}
```
### Свойства:
* Космическая сложность: O (1)
* Сложность времени: O (n), O (n \* n), O (n \* n) для лучших, средних, худших случаев соответственно
* Сортировка на месте: Да
* Стабильный: Да
#### Другие источники:
* [Википедия](https://en.wikipedia.org/wiki/Insertion_sort)
* [CS50 - YouTube](https://youtu.be/TwGb6ohsvUU)
* [SortInsertion - GeeksforGeeks, YouTube](https://www.youtube.com/watch?v=wObxd4Kx8sE)
* [Вставка Сортировка Визуализация](https://www.hackerearth.com/practice/algorithms/sorting/insertion-sort/visualize/)

View File

@@ -0,0 +1,204 @@
---
title: Merge Sort
localeTitle: Объединить сортировку
---
## Сортировка слиянием
Merge Sort - алгоритм [Divide и Conquer](https://guide.freecodecamp.org/algorithms/divide-and-conquer-algorithms) . Он делит входной массив на две половины, вызывает себя для двух половинок, а затем объединяет две отсортированные половинки. Основная часть алгоритма дается двумя отсортированными массивами, мы должны объединить их в один отсортированный массив. Существует нечто, известное как « [Алгоритм](http://www.geeksforgeeks.org/merge-two-sorted-arrays/) с [двумя пальцами»,](http://www.geeksforgeeks.org/merge-two-sorted-arrays/) который помогает нам объединить два отсортированных массива вместе. Используя эту подпрограмму и вызывая функцию сортировки слияния на ребрах массива, мы дадим окончательный отсортированный массив, который мы ищем.
Так как это алгоритм, основанный на рекурсии, у нас есть рекуррентное соотношение для него. Рекуррентное отношение - это просто способ представления проблемы в терминах ее подзадач.
`T(n) = 2 * T(n / 2) + O(n)`
Поставив это на простом английском языке, мы разбиваем подзадачу на две части на каждом шагу, и у нас есть некоторый линейный объем работы, который мы должны сделать для слияния двух отсортированных половин на каждом шаге.
```
T(n) = 2T(n/2) + n
= 2(2T(n/4) + n/2) + n
= 4T(n/4) + n + n
= 4(2T(n/8) + n/4) + n + n
= 8T(n/8) + n + n + n
= nT(n/n) + n + ... + n + n + n
= n + n + ... + n + n + n
```
Подсчитая количество повторений n в сумме в конце, мы видим, что есть lg n + 1 из них. Таким образом, время работы n (lg n + 1) = n lg n + n. Заметим, что n lg n + n <n lg n + n lg n = 2n lg n при n> 0, поэтому время работы O (n lg n).
```Algorithm
MergeSort(arr[], left, right):
If right > l:
1. Find the middle point to divide the array into two halves:
mid = (left+right)/2
2. Call mergeSort for first half:
Call mergeSort(arr, left, mid)
3. Call mergeSort for second half:
Call mergeSort(arr, mid+1, right)
4. Merge the two halves sorted in step 2 and 3:
Call merge(arr, left, mid, right)
```
![Merge Sort Algorithm](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Merge_sort_algorithm_diagram.svg/300px-Merge_sort_algorithm_diagram.svg.png)
### Properties:
* Space Complexity: O(n)
* Time Complexity: O(n*log(n)). The time complexity for the Merge Sort might not be obvious from the first glance. The log(n) factor that comes in is because of the recurrence relation we have mentioned before.
* Sorting In Place: No in a typical implementation
* Stable: Yes
* Parallelizable :yes (Several parallel variants are discussed in the third edition of Cormen, Leiserson, Rivest, and Stein's Introduction to Algorithms.)
### Visualization:
* <a href='https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html'>USFCA</a>
* <a href='https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/visualize/'>HackerEarth</a>
### Relavant videos on freeCodeCamp YouTube channel
* <a href='https://youtu.be/TzeBrDU-JaY'>Merge Sort algorithm - MyCodeSchool</a>
### Other Resources:
* <a href='https://en.wikipedia.org/wiki/Merge_sort' target='_blank' rel='nofollow'>Wikipedia</a>
* <a href='www.geeksforgeeks.org/merge-sort' target='_blank' rel='nofollow'>GeeksForGeeks</a>
* <a href='https://youtu.be/sWtYJv_YXbo' target='_blank' rel='nofollow'>Merge Sort - CS50</a>
### Implementaion in JS
```
JS const list = \[23, 4, 42, 15, 16, 8, 3\]
const mergeSort = (list) => { if (list.length <= 1) возвращаемый список; const средний = list.length / 2; const left = list.slice (0, средний); const right = list.slice (средний, list.length); return merge (mergeSort (слева), mergeSort (справа)); }
const merge = (слева, справа) => { var result = \[\]; while (left.length || right.length) { if (left.length && right.length) { if (left \[0\] <right \[0\]) { result.push (left.shift ()) } else { result.push (right.shift ()) } } else if (left.length) { result.push (left.shift ()) } else { result.push (right.shift ()) } } результат возврата; }
console.log (mergeSort (список)) // \[3, 4, 8, 15, 16, 23, 42\]
```
### Implementation in C
```
С
# включают
# включают
void merge (int arr \[\], int l, int m, int r) { int i, j, k; int n1 = m - l + 1; int n2 = r - m;
```
int L[n1], R[n2];
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
```
}
void mergeSort (int arr \[\], int l, int r) { если (l <r) {
int m = l + (rl) / 2;
```
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
```
} void printArray (int A \[\], int size) { int i; для (i = 0; i <size; i ++) printf ("% d", A \[i\]); Е ( "\\ п"); } int main () { int arr \[\] = {12, 11, 13, 5, 6, 7}; int arr\_size = sizeof (arr) / sizeof (arr \[0\]);
```
printf("Given array is \n");
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
printf("\nSorted array is \n");
printArray(arr, arr_size);
return 0;
```
```
### Implementation in C++
Let us consider array A = {2,5,7,8,9,12,13}
and array B = {3,5,6,9,15} and we want array C to be in ascending order as well.
```
C ++ void mergesort (int A \[\], int size _a, int B \[\], int size_ b, int C \[\]) { int token _a, токен_ b, токен _c; for (токен_ a = 0, токен _b = 0, токен_ c = 0, токен _a_ _a && токен _b__ __б; ) { если (A \[токен _a\] <= B \[токен_ b\]) C \[токен _c ++\] = A \[токен_ a ++\]; еще C \[токен _c ++\] = B \[токен_ b ++\]; }__
```
if(token_a<size_a)
{
while(token_a<size_a)
C[token_c++]=A[token_a++];
}
else
{
while(token_b<size_b)
C[token_c++]=B[token_b++];
}
```
}
```
### Implementation in Python
```
питон temp = None def merge (arr, слева, справа): глобальные темпы, инверсии mid = (left + right) // 2 для i в диапазоне (слева, справа + 1): temp \[i\] = arr \[i\]
```
k, L, R = left, left, mid + 1
while L <= mid and R <= right:
if temp[L] <= temp[R]:
arr[k] = temp[L]
L += 1
else:
arr[k] = temp[R]
R += 1
k += 1
while L <= mid:
arr[k] = temp[L]
L += 1
k += 1
while R <= right:
arr[k] = temp[R]
R += 1
k += 1
```
def merge\_sort (arr, слева, справа): если left> = right: вернуть
```
mid = (left + right) // 2
merge_sort(arr, left, mid)
merge_sort(arr, mid + 1, right)
merge(arr, left, right)
```
arr = \[1,6,3,1,8,4,2,9,3\] temp = \[Нет для \_ в диапазоне (len (arr))\] merge\_sort (arr, 0, len (arr) - 1) print (arr, inversions) \`\` \`

View File

@@ -0,0 +1,146 @@
---
title: Quick Sort
localeTitle: Быстрая сортировка
---
## Быстрая сортировка
Быстрая сортировка - эффективный алгоритм сортировки и разделения. Средняя временная сложность Quick Sort - O (nlog (n)) с наихудшей временной сложностью - O (n ^ 2).
Шаги, связанные с Quick Sort:
* Выберите элемент, который будет служить точкой опоры, в этом случае последним элементом массива является опорная точка.
* Разделение: сортировка массива таким образом, чтобы все элементы, меньшие, чем точка поворота, находились влево, а все элементы, большие, чем точка поворота, находились вправо.
* Вызовите Quicksort рекурсивно, учитывая предыдущий шарнир, чтобы правильно разделить левый и правый массивы. (Более подробное объяснение можно найти в комментариях ниже)
Быстрая реализация в JavaScript:
```javascript
const arr = [6, 2, 5, 3, 8, 7, 1, 4]
const quickSort = (arr, start, end) => {
if(start < end) {
// You can learn about how the pivot value is derived in the comments below
let pivot = partition(arr, start, end)
// Make sure to read the below comments to understand why pivot - 1 and pivot + 1 are used
// These are the recursive calls to quickSort
quickSort(arr, start, pivot - 1)
quickSort(arr, pivot + 1, end)
}
}
const partition = (arr, start, end) => {
let pivot = end
// Set i to start - 1 so that it can access the first index in the event that the value at arr[0] is greater than arr[pivot]
// Succeeding comments will expound upon the above comment
let i = start - 1
let j = start
// Increment j up to the index preceding the pivot
while (j < pivot) {
// If the value is greater than the pivot increment j
if (arr[j] > arr[pivot]) {
j++
}
// When the value at arr[j] is less than the pivot:
// increment i (arr[i] will be a value greater than arr[pivot]) and swap the value at arr[i] and arr[j]
else {
i++
swap(arr, j, i)
j++
}
}
//The value at arr[i + 1] will be greater than the value of arr[pivot]
swap(arr, i + 1, pivot)
//You return i + 1, as the values to the left of it are less than arr[i+1], and values to the right are greater than arr[i + 1]
// As such, when the recursive quicksorts are called, the new sub arrays will not include this the previously used pivot value
return i + 1
}
const swap = (arr, firstIndex, secondIndex) => {
let temp = arr[firstIndex]
arr[firstIndex] = arr[secondIndex]
arr[secondIndex] = temp
}
quickSort(arr, 0, arr.length - 1)
console.log(arr)
```
Быстрая сортировка в C
```C
#include<stdio.h>
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
int partition (int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high- 1; j++)
{
if (arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
void quickSort(int arr[], int low, int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
printf("n");
}
int main()
{
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr)/sizeof(arr[0]);
quickSort(arr, 0, n-1);
printf("Sorted array: n");
printArray(arr, n);
return 0;
}
```
Сложность пространства быстрой сортировки - O (n). Это улучшение по сравнению с другими алгоритмами сортировки и разделения, которые занимают пространство O (nlong (n)). Быстрая сортировка достигает этого, изменяя порядок элементов в заданном массиве. Сравните это с алгоритмом [сортировки слиянием](https://guide.freecodecamp.org/algorithms/sorting-algorithms/merge-sort) , который создает в каждом вызове функции 2 массива, каждая длина n / 2.
#### Дополнительная информация:
* [Википедия](https://en.wikipedia.org/wiki/Quicksort)
* [GeeksForGeeks](http://www.geeksforgeeks.org/quick-sort)
* [Youtube: визуальное объяснение Quicksort](https://www.youtube.com/watch?v=MZaf_9IZCrc)
* [Youtube: Gayle Laakmann McDowell (автор Cracking the Coding Interview) объясняет основы быстрой сортировки и демонстрирует некоторые реализации](https://www.youtube.com/watch?v=SLauY6PpjW4)

View File

@@ -0,0 +1,111 @@
---
title: Radix Sort
localeTitle: Radix Sort
---
## Radix Sort
Предпосылки: подсчет сортировки
QuickSort, MergeSort, HeapSort - это алгоритмы сортировки на основе сравнения. CountSort не является алгоритмом, основанным на сравнении. Он имеет сложность O (n + k), где k - максимальный элемент входного массива. Таким образом, если k является O (n), CountSort становится линейной сортировкой, что лучше, чем алгоритмы сортировки на основе сравнения, которые имеют сложность времени O (nlogn). Идея состоит в том, чтобы расширить алгоритм CountSort, чтобы получить лучшую временную сложность, когда k идет O (n2). Приходит идея Radix Sort.
Алгоритм:
Для каждой цифры i, где i изменяется от младшей значащей цифры до самой значащей цифры числа Сортировка массива ввода с использованием алгоритма countsort в соответствии с i-й цифрой. Мы использовали сортировку count, потому что это стабильный вид.
Пример. Предположим, что входной массив:
10,21,17,34,44,11,654,123
На основе алгоритма мы сортируем входной массив в соответствии с его цифрой (наименьшая значащая цифра).
0: 10
1: 21 11
2:
3: 123
4: 34 44 654
5:
6:
7: 17
8:
9:
Таким образом, массив становится 10,21,11,123,24,44,654,17 Теперь мы будем сортировать по десятизначной цифре:
0:
1: 10 11 17
2: 21 123
3: 34
4: 44
5: 654
6:
7:
8:
9:
Теперь массив становится следующим: 10,11,17,21,123,34,44,654 Наконец, мы сортируем по ста цифре (самая значительная цифра):
0: 010 011 017 021 034 044
1: 123
2:
3:
4:
5:
6: 654
7:
8:
9:
Массив становится: 10,11,17,21,34,44,123,654, который сортируется. Так работает наш алгоритм.
Реализация в C:
```
void countsort(int arr[],int n,int place){
int i,freq[range]={0}; //range for integers is 10 as digits range from 0-9
int output[n];
for(i=0;i<n;i++)
freq[(arr[i]/place)%range]++;
for(i=1;i<range;i++)
freq[i]+=freq[i-1];
for(i=n-1;i>=0;i--){
output[freq[(arr[i]/place)%range]-1]=arr[i];
freq[(arr[i]/place)%range]--;
}
for(i=0;i<n;i++)
arr[i]=output[i];
}
void radixsort(ll arr[],int n,int maxx){ //maxx is the maximum element in the array
int mul=1;
while(maxx){
countsort(arr,n,mul);
mul*=10;
maxx/=10;
}
}
```
### Дополнительная информация:
* [Википедия](https://en.wikipedia.org/wiki/Radix_sort)
* [GeeksForGeeks](http://www.geeksforgeeks.org/radix-sort/)

View File

@@ -0,0 +1,67 @@
---
title: Selection Sort
localeTitle: Выбор Сортировка
---
## Выбор Сортировка
Выбор Сортировка - один из самых простых алгоритмов сортировки. Он работает следующим образом,
1. Найдите наименьший элемент. Поменяйте его первым элементом.
2. Найдите второй наименьший элемент. Поменяйте его на второй элемент.
3. Найдите третий наименьший элемент. Поменяйте его третьим элементом.
4. Повторите поиск следующего наименьшего элемента и переместите его в соответствующее правильное положение до сортировки массива.
Как вы можете догадаться, этот алгоритм называется Selection Sort, потому что он многократно выбирает следующий наименьший элемент и меняет его на свое место.
Но как бы вы написали код для поиска индекса второго наименьшего значения в массиве?
* Легкий способ заметить, что наименьшее значение уже было заменено на индекс 0, поэтому проблема сводится к поиску наименьшего элемента в массиве, начиная с индекса 1.
### Реализация в C / C ++
```C
for(int i = 0; i < n; i++)
{
int min_index = i;
int min_element = a[i];
for(int j = i +1; j < n; j++)
{
if(a[j] < min_element)
{
min_element = a[j];
min_index = j;
}
}
swap(&a[i], &a[min_index]);
}
```
### Реализация в Javascript
\`\` \`Javascript _сортировка_ функции _(A) { var len =_ длина ассива_ (A); для (var i = 0; i <len - 1; i = i + 1) { var j _min = i; для (var j = i + 1; j <len; j = j + 1) { если (A \[j\] <A \[j_ min\]) { j _min = j; } else {} } if (j_ min! == i) { swap (A, i, j\_min); } else {} } }
функция swap (A, x, y) { var temp = A \[x\]; A \[x\] = A \[y\]; A \[y\] = temp; }
```
### Implementation in Python
```
питон def seletion _sort (arr): если не обр: return arr для i в диапазоне (len (arr)): min_ i = i для j в диапазоне (i + 1, len (arr)): если arr \[j\] <arr \[min _i\]: min_ i = j arr \[i\], arr \[min _i\] = arr \[min_ i\], arr \[i\] \`\` \`
### свойства
* Космическая сложность: **O (n)**
* Сложность времени: **O (n 2 )**
* Сортировка на месте: **Да**
* Стабильный: **Нет**
### Визуализация
* [USFCA](https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html)
* [HackerEarth](https://www.hackerearth.com/practice/algorithms/sorting/selection-sort/visualize/)
### Рекомендации
* [Википедия](https://en.wikipedia.org/wiki/Selection_sort)
* [Академия Хана](https://www.khanacademy.org/computing/computer-science/algorithms#sorting-algorithms)

View File

@@ -0,0 +1,112 @@
---
title: Timsort
localeTitle: Timsort
---
## Timsort
Timsort - это быстрый алгоритм сортировки, который работает при стабильной сложности O (N log (N))
Timsort - это смесь в Sorting Sorting и Mergesort. Этот алгоритм реализован в Java Arrays.sort (), а также в отсортированных () и sort () Меньшая часть сортируется с помощью метода «Сортировка вставки» и позже объединяется с использованием Mergesort.
Быстрая реализация в Python:
```
def binary_search(the_array, item, start, end):
if start == end:
if the_array[start] > item:
return start
else:
return start + 1
if start > end:
return start
mid = round((start + end)/ 2)
if the_array[mid] < item:
return binary_search(the_array, item, mid + 1, end)
elif the_array[mid] > item:
return binary_search(the_array, item, start, mid - 1)
else:
return mid
"""
Insertion sort that timsort uses if the array size is small or if
the size of the "run" is small
"""
def insertion_sort(the_array):
l = len(the_array)
for index in range(1, l):
value = the_array[index]
pos = binary_search(the_array, value, 0, index - 1)
the_array = the_array[:pos] + [value] + the_array[pos:index] + the_array[index+1:]
return the_array
def merge(left, right):
"""Takes two sorted lists and returns a single sorted list by comparing the
elements one at a time.
[1, 2, 3, 4, 5, 6]
"""
if not left:
return right
if not right:
return left
if left[0] < right[0]:
return [left[0]] + merge(left[1:], right)
return [right[0]] + merge(left, right[1:])
def timsort(the_array):
runs, sorted_runs = [], []
length = len(the_array)
new_run = [the_array[0]]
# for every i in the range of 1 to length of array
for i in range(1, length):
# if i is at the end of the list
if i == length - 1:
new_run.append(the_array[i])
runs.append(new_run)
break
# if the i'th element of the array is less than the one before it
if the_array[i] < the_array[i-1]:
# if new_run is set to None (NULL)
if not new_run:
runs.append([the_array[i]])
new_run.append(the_array[i])
else:
runs.append(new_run)
new_run = []
# else if its equal to or more than
else:
new_run.append(the_array[i])
# for every item in runs, append it using insertion sort
for item in runs:
sorted_runs.append(insertion_sort(item))
# for every run in sorted_runs, merge them
sorted_array = []
for run in sorted_runs:
sorted_array = merge(sorted_array, run)
print(sorted_array)
timsort([2, 3, 1, 5, 6, 7])
```
#### Сложность:
Сорт Tim имеет стабильную сложность O (N log (N)) и очень хорошо сравнивается с Quicksort. На этой [диаграмме](https://cdn-images-1.medium.com/max/1600/1*1CkG3c4mZGswDShAV9eHbQ.png) можно найти совпадение сложностей
#### Дополнительная информация:
* [Википедия](https://en.wikipedia.org/wiki/Timsort)
* [GeeksForGeeks](https://www.geeksforgeeks.org/timsort/)
* [Youtube: визуальное объяснение Quicksort](https://www.youtube.com/watch?v=jVXsjswWo44)
#### Кредиты:
[Реализация Python](https://hackernoon.com/timsort-the-fastest-sorting-algorithm-youve-never-heard-of-36b28417f399)

View File

@@ -0,0 +1,46 @@
---
title: Rabin Karp Algorithm
localeTitle: Алгоритм Рабина Карпа
---
## Алгоритм Рабина-Карпа
* Алгоритм поиска / поиска строк, разработанный Майклом О. Рабиным и Ричардом М. Карпом.
* Использует метод **_хэширования_** и **_грубую силу_** для сравнения.
#### Важные условия
* **_pattern_** - строка, подлежащая поиску. Рассмотрим длину шаблона как **_M_** символов.
* **_текст_** - это весь текст, из которого следует искать шаблон. Рассмотрим длину текста как **_N_** символов.
#### Что такое сравнение грубой силы?
При сравнении грубой силы каждый символ шаблона сравнивается с каждым символом текста до тех пор, пока не будут найдены символы, не соответствующие символу.
#### Работа алгоритма Рабина-Карпа
1. Рассчитать хэш-значение аблона_
2. Рассчитать хэш-значение первых _M_ символов екста_
3. Сравните оба значения хэша
4. Если они не равны, вычислите хэш-значение для следующих _M_ символов екста_ и сравните их снова.
5. Если они равны, выполните сравнение грубой силы.
```
hash_p = hash value of pattern
hash_t = hash value of first M letters in body of text
do
if (hash_p == hash_t)
brute force comparison of pattern and selected section of text
hash_t= hash value of next section of text, one character over
while (end of text or brute force comparison == true)
```
#### Преимущество над алгоритмом наивного строкового соответствия
Этот метод приводит только к одному сравнению для каждой подпоследовательности текста, и грубая сила требуется только тогда, когда значения хэша совпадают.
#### Приложения
* **_Обнаружение плагиата_**
#### Дополнительная информация:
[Рабин-Карп в Википедии](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm/)