Разложение на множители (факторизация) — различия между версиями
Senya (обсуждение | вклад) (→Псевдокод) (Метки: правка с мобильного устройства, правка из мобильной версии) |
м (rollbackEdits.php mass rollback) |
||
(не показаны 24 промежуточные версии 6 участников) | |||
Строка 3: | Строка 3: | ||
}} | }} | ||
{{Определение | definition= | {{Определение | definition= | ||
− | '''Разложение на множители''', или '''Факторизация целых чисел''' (англ. ''integer factorization'') — представление числа в виде [[ | + | '''Разложение на множители''', или '''Факторизация целых чисел''' (англ. ''integer factorization'') — представление числа в виде [[Натуральные числа#Основная теорема арифметики | произведения его множителей]]. |
}} | }} | ||
== Перебор делителей== | == Перебор делителей== | ||
{{Определение | definition= | {{Определение | definition= | ||
− | '''Перебор делителей''' (англ. ''Trial division'') — алгоритм факторизации или тестирования простоты числа путем полного перебора всех возможных потенциальных делителей. | + | '''Перебор делителей''' (англ. ''Trial division'') — алгоритм для факторизации или тестирования простоты числа путем полного перебора всех возможных потенциальных делителей. |
}} | }} | ||
=== Наивная реализация O(n) === | === Наивная реализация O(n) === | ||
− | [[Основная теорема арифметики#Основная теорема арифметики#Собственно теорема | Основная теорема арифметики]], | + | [[Основная теорема арифметики#Основная теорема арифметики#Собственно теорема | Основная теорема арифметики]], вкупе с утверждением, что <tex>y</tex> не делит <tex>x</tex> нацело: <tex>\forall x, y \in \mathbb{N}~~x<y \Longrightarrow</tex> <tex>\left( \dfrac{x}{y} < 1 \right)</tex>, позволяют нам ограничить пространство поиска делителей числа <tex>number</tex> интервалом <tex>[2;number]</tex>. |
==== Основная идея ==== | ==== Основная идея ==== | ||
− | Заметим, что если <tex>number</tex> = <tex>\prod p_i = p_1 \cdot p_2 \cdot \ldots \cdot p_{j-1} \cdot p_j \cdot p_{j+1} \cdot \ldots \cdot p_n</tex>, то <tex>\left(\dfrac{number}{p_j}\right) = \prod\limits_{i \ne j} p_i = p_1 \cdot p_2 \cdot \ldots \cdot p_{j-1} \cdot p_{j+1} \cdot \ldots \cdot p_n</tex>. Таким образом, мы можем делить <tex>number</tex> на его делители(множители) последовательно и в любом порядке. Тогда будем хранить <tex>curNum \colon curNum = \dfrac{number}{\prod result_i}</tex> — произведение оставшихся множителей. | + | Заметим, что если <tex>number</tex> = <tex>\prod p_i = p_1 \cdot p_2 \cdot \ldots \cdot p_{j-1} \cdot p_j \cdot p_{j+1} \cdot \ldots \cdot p_n</tex>, то <tex>\left(\dfrac{number}{p_j}\right) = \prod\limits_{i \ne j} p_i = p_1 \cdot p_2 \cdot \ldots \cdot p_{j-1} \cdot p_{j+1} \cdot \ldots \cdot p_n</tex>. Таким образом, мы можем делить <tex>number</tex> на его делители (множители) последовательно и в любом порядке. Тогда будем хранить <tex>curNum \colon curNum = \dfrac{number}{\prod result_i}</tex> — произведение оставшихся множителей. |
==== Псевдокод нахождения простых множителей ==== | ==== Псевдокод нахождения простых множителей ==== | ||
− | + | Так как простых множителей не может быть больше, чем <tex>n</tex>, а в худшем случае (когда число простое, и на каждое итерации <tex>probe</tex> увеличивается на <tex>1</tex>) он работает за <tex>O(n)</tex>, то, следовательно, алгоритм работает за <tex>O(n)</tex>. | |
'''function''' getMultipliers(number: '''int'''): '''vector<int>''' | '''function''' getMultipliers(number: '''int'''): '''vector<int>''' | ||
Строка 68: | Строка 68: | ||
'''return''' result | '''return''' result | ||
− | === Проверка числа на простоту | + | === Проверка числа на простоту === |
− | Алгоритм можно переделать для нахождения простых чисел. Число будет простым, если у него не окажется | + | Алгоритм можно переделать для нахождения простых чисел. Число будет простым, если у него не окажется множителей (и делителей) кроме <tex>1</tex> (алгоритмы не проверяют делимость на <tex>1</tex>) и самого числа (улучшенная реализация опускает этот делитель). |
− | |||
− | |||
== Предподсчет == | == Предподсчет == | ||
Строка 80: | Строка 78: | ||
<font color=green>// возвращает только дополнительный массив</font> | <font color=green>// возвращает только дополнительный массив</font> | ||
− | '''function''' sieveOfEratosthenes(n: '''int'''): '''int'''[n] | + | '''function''' sieveOfEratosthenes(n: '''int'''): '''int'''[n + 1] |
− | result = [n] | + | result = [n + 1] |
+ | result[n] = n | ||
<font color=green>// выбираем следующий простой делитель</font> | <font color=green>// выбираем следующий простой делитель</font> | ||
− | '''for''' i = 2 '''to''' <tex>\sqrt{n}</tex> | + | '''for''' i = 2 '''to''' <tex>\sqrt{n}</tex> |
− | '''if''' result[i] | + | '''if''' result[i] = 0 |
<font color=green>// записываем делитель в элементы массива, | <font color=green>// записываем делитель в элементы массива, | ||
// соответствующие числа которых делятся нацело</font> | // соответствующие числа которых делятся нацело</font> | ||
Строка 100: | Строка 99: | ||
// делением предыдущего на простой делитель из решета</font> | // делением предыдущего на простой делитель из решета</font> | ||
curNum = number | curNum = number | ||
− | '''while''' | + | '''while''' curNum <tex>\ne</tex> 1 |
− | result += [ | + | result += sieve[curNum] |
curNum /= sieve[curNum] | curNum /= sieve[curNum] | ||
− | |||
'''return''' result | '''return''' result | ||
Строка 116: | Строка 114: | ||
[[Категория: Алгоритмы алгебры и теории чисел]] | [[Категория: Алгоритмы алгебры и теории чисел]] | ||
+ | [[Категория: Теория чисел]] |
Текущая версия на 19:17, 4 сентября 2022
Определение: |
Факторизация (англ. factorization) — представление объекта в виде произведения других объектов. |
Определение: |
Разложение на множители, или Факторизация целых чисел (англ. integer factorization) — представление числа в виде произведения его множителей. |
Перебор делителей
Определение: |
Перебор делителей (англ. Trial division) — алгоритм для факторизации или тестирования простоты числа путем полного перебора всех возможных потенциальных делителей. |
Наивная реализация O(n)
Основная теорема арифметики, вкупе с утверждением, что не делит нацело: , позволяют нам ограничить пространство поиска делителей числа интервалом .
Основная идея
Заметим, что если
= , то . Таким образом, мы можем делить на его делители (множители) последовательно и в любом порядке. Тогда будем хранить — произведение оставшихся множителей.Псевдокод нахождения простых множителей
Так как простых множителей не может быть больше, чем
, а в худшем случае (когда число простое, и на каждое итерации увеличивается на ) он работает за , то, следовательно, алгоритм работает за .function getMultipliers(number: int): vector<int> // сюда складываем множители result = vector<int> // число, у которого осталось найти множители curNum = number // число, на которое пытаемся делить probe = 2 while curNum1 if curNum mod probe 0 // проверены все множители из [2; probe] probe++ else // делим пока делится curNum /= probe result += [probe] return result
Псевдокод нахождения делителей
function getDividers(number: int): vector<int> // массив полученных делителей result = vector<int> // перебираем все потенциальные делители for probe = 2 to number if number mod probe = 0 // probe делит number нацело result += [probe] return result
Улучшенная реализация
Основная идея
Из определения:
. Логично, что:Таким образом, любой делитель
однозначно связан с некоторым . Если мы найдем все делители до , задача может считаться решенной.Псевдокод
function getDividers(number: int): vector<int>
result = vector<int>
for probe = 2 to
//обновляем верхнюю границу перебора
if number mod probe = 0
result += [probe]
result += [number / probe] // записываем сопряженный делитель
return result
Проверка числа на простоту
Алгоритм можно переделать для нахождения простых чисел. Число будет простым, если у него не окажется множителей (и делителей) кроме
(алгоритмы не проверяют делимость на ) и самого числа (улучшенная реализация опускает этот делитель).Предподсчет
Основная идея
Решето Эратосфена (англ. Sieve of Eratosthenes) позволяет не только находить простые числа, но и находить простые множители числа. Для этого необходимо хранить (помимо самого "решета") массив простых чисел, на которое каждое число делится (достаточно одного простого делителя).
Псевдокод
// возвращает только дополнительный массив function sieveOfEratosthenes(n: int): int[n + 1] result = [n + 1] result[n] = n // выбираем следующий простой делитель for i = 2 toif result[i] = 0 // записываем делитель в элементы массива, // соответствующие числа которых делятся нацело shuttle = while shuttle n result[shuttle] = i shuttle += i return result
function getMultipliers(number: int): vector<int>
result = vector<int>
// получаем дополненное решето Эратосфена
sieve = sieveOfEratosthenes(number)
// следующее временное значение получаем
// делением предыдущего на простой делитель из решета
curNum = number
while curNum
1
result += sieve[curNum]
curNum /= sieve[curNum]
return result
См. также
Источники информации
- Маврин П.Ю. — Лекция по алгоритмам над простыми числами (2016)
- https://ru.wikipedia.org/wiki/Простое_число