344
правки
Изменения
дефисы заменить на тире, там же должно быть тире, английские термины, сделать псевдокод одинаковым во всех частях статьи
{{Определение | definition=
''Факторизация'' - (англ. ''factorization'') — представление объекта в виде произведения других объектов.
}}
{{Определение | definition=
''Разложение на множители'', или ''Факторизация целых чисел'' - (англ. ''integer factorization'') — представление числа в виде [[Основная теорема арифметики#Основная теорема арифметики#Собственно теорема | произведения его множителей]].
}}
{{Определение | definition=
''Перебор делителей'' — алгоритм факторизации или тестирования простоты числа путем полного перебора всех возможных потенциальных делителей.
}}
== Перебор делителей (англ. ''Trial division'')==
=== Наивная реализация <tex>O(n)</tex> ===
==== Основная идея ====
[[Основная теорема арифметики#Основная теорема арифметики#Собственно теорема | Основная теорема арифметики]], в купе с утверждением, что <tex>\forall x, y \in \mathbb{N}~~x<y \Longrightarrow</tex> {{Acronym|<tex>\left( \dfrac{x}{y} < 1 \right)</tex>|т.е. y не делит x нацело}}, позволяют нам ограничить пространство поиска делителей числа <tex>\mathtt{number}</tex> интервалом <tex>[2; \mathtt{number}]</tex>.
Заметим, что если <tex>\mathtt{number} = \prod p_i = p_1 * p_2 * \dots * p_{j-1} * p_j * p_{j+1} * \dots * p_n</tex>, то <tex>\left(\dfrac{\mathtt{number}}{p_i}\right) = \prod\limits_{i \ne j} p_i = p_1 * p_2 * \dots * p_{j-1} * p_{j+1} * \dots * p_n</tex>. Таким образом, мы можем делить <tex>\mathtt{number}</tex> на его {{Acronym|делители|множители}} последовательно и в любом порядке. Тогда будем хранить <tex>\mathtt{curNum} \colon \mathtt{curNum} * \prod \mathtt{result_i} =\mathtt{number}</tex> - — произведение оставшихся множителей.
==== Псевдокод нахождения простых множителей ====
Алгоритм работает за <tex>O(k)</tex>, где k - — количество простых множителей.
<code>
'''function''' <tex>\mathrm{getMultipliers}</tex>(number: '''int'''): '''vector<int>'''
<font color=green>// сюда складываем множители</font>
result = '''vector<int>'''
<font color=green>// число, у которого осталось найти множители; </font>
curNum = number
<font color=green>// число, на которое пытаемся делить</font>
==== Псевдокод нахождения делителей ====
<code>
'''function''' <tex>\mathrm{getDividers}</tex>(number: '''int'''): '''vector<int>'''
<font color=green>// массив полученных делителей</font>
result = '''vector<int>'''
|-align="center"
|rowspan="2"| <tex>\bigg\{</tex>
|<tex>x * y = \mathtt{number}</tex>|rowspan="2"| <tex>\Longrightarrow x > \sqrt{\mathtt{number}}</tex>
|-align="center"
|<tex>y < \sqrt{\mathtt{number}}</tex>
|}
Таким образом, любой делитель <tex>d_0 > \sqrt{\mathtt{number}}</tex> однозначно связан с некоторым <tex>d_1 < \sqrt{\mathtt{number}}</tex>. Если мы найдем все делители до <tex>\sqrt{\mathtt{number}}</tex>, задача может считаться решенной.
==== Псевдокод ====
<code>
'''function''' <tex>\mathrm{getDividers}</tex>(<tex>\mathtt{number}</tex>: '''int'''): '''vector<int>'''
result = '''vector<int>'''
'''for''' probe = 2 '''to''' <tex>\sqrt{\mathtt{number}}</tex> <font color=green>// <--- обновляем верхнюю границу перебора</font> '''if''' number '''mod''' probe = 0
result += [probe]
result += [<tex>\mathtt{number}</tex> / probe] <font color=green>// <--- записываем сопряженный делитель</font>
'''return''' result
</code>
=== Проверка числа на простоту. Множители ===
Алгоритм можно переделать для нахождения простых чисел. Число будет простым, если у него не окажется {{Acronym|множителей|и делителей}} кроме 1 (алгоритмы не проверяют делимость на 1) и самого числа (улучшенная реализация опускает этот делитель). Исключительный случай: <tex>\mathtt{number} = 2</tex>.
Вообще говоря, представленный выше алгоритм <tex>\mathrm{getMultipliers}</tex> ищет простые множители. Чтобы получить разложения на множители необходимо реализовать [[Генерация комбинаторных объектов в лексикографическом порядке|перебор разбиений]] мультимножества простых множителей на подмножества, тогда, перемножив элементы подмножеств, мы получим множители.
{{main|Решето Эратосфена}}
=== Основная идея ===
Решето Эратосфена (англ. ''Sieve of Eratosthenes'') позволяет не только находить простые числа, но и находить простые множители числа. Для этого необходимо хранить (помимо самого "решета") массив простых чисел, на которое каждое число делится (достаточно одного простого делителя).
=== Псевдокод ===
<code>
<font color=green>// возвращает только дополнительный массив</font>
'''function''' <tex>\mathrm{sieveOfEratosthenes}</tex>(n: '''int'''): '''int'''[n]'''
result = [n]
<font color=green>// выбираем следующий простой делитель</font>
'''for''' i = 2 '''to''' <tex>\sqrt{\mathtt{n}}</tex>
'''if''' result[i] <tex>\ne</tex> ''null''
<font color=green>// {{Acronym|записываем |в этой реализации и переписываем тоже}}делитель в элементы массива,
// соответствующие числа которых делятся нацело</font>
shuttle = <tex>\mathtt{i}^2</tex>
'''while''' shuttle <tex>\leqslant</tex> n
result[shuttle] = i
'''return''' result
'''function''' <tex>\mathrm{getMultipliers}</tex>(number: '''int'''): '''vector<int>'''
result = '''vector<int>'''
<font color=green>// получаем дополненное решето Эратосфена</font>
sieve = <tex>\mathrm{sieveOfEratosthenes}</tex>(number)
<font color=green>// следующее временное значение получаем
// делением предыдущего на простой делитель из решета</font>
'''return''' result
</code>
== Источники информации ==
* Маврин П.Ю. — Лекция по алгоритмам над простыми числами (2016)
* [https://ru.wikipedia.org/wiki/Простое_число https://ru.wikipedia.org/wiki/Простое_число]
== См. также ==
*[[Решето Эратосфена]]
*[[Основная теорема арифметики]]
*[[Дискретная математика, алгоритмы и структуры данных#Комбинаторика | Комбинаторика]]
[[Категория: Алгоритмы алгебры и теории чисел]]