2010-05-16 16 views
16

Co może być najprostszą i wydajną logiką, aby dowiedzieć się o czynnikach z danego Numeru. Czy istnieje algorytm, który istnieje, oparty na tym samym.Algorytm znajdowania czynników danej liczby. Najkrótsza metoda?

Właściwie moim prawdziwym problemem jest odkrycie nr. czynników, które istnieją dla danej liczby ..

więc każdy algorytm, proszę dać mi znać o tym ..

Dzięki.

+2

Najkrótsza w kodzie lub czasie wykonania? – meriton

+1

Czy pytanie zostało zainspirowane przez jeden z problemów związanych z projektowaniem? –

+0

@Meriton - Najkrótszy w znalezieniu rozwiązania. – AGeek

Odpowiedz

19

Właściwie moim prawdziwym problemem jest odkrycie nr. czynników istniejących dla danego numeru.

Cóż, jest inaczej. Niech n będzie podaną liczbą.

Jeśli n = p1^e1 * p2^e2 * ... * pk^ek, gdzie każdy p jest liczbą pierwszą, to liczba czynników n jest (e1 + 1)*(e2 + 1)* ... *(ek + 1). Więcej na ten temat here.

Dlatego wystarczy znaleźć moce, w których pojawia się każdy czynnik główny. Na przykład:

read given number in n 
initial_n = n 
num_factors = 1; 
for (i = 2; i * i <= initial_n; ++i) // for each number i up until the square root of the given number 
{ 
    power = 0; // suppose the power i appears at is 0 
    while (n % i == 0) // while we can divide n by i 
    { 
     n = n/i // divide it, thus ensuring we'll only check prime factors 
     ++power // increase the power i appears at 
    } 
    num_factors = num_factors * (power + 1) // apply the formula 
} 

if (n > 1) // will happen for example for 14 = 2 * 7 
{ 
    num_factors = num_factors * 2 // n is prime, and its power can only be 1, so multiply the number of factors by 2 
} 

Na przykład weź 18. 18 = 2^1 * 3*2 => number of factors = (1 + 1)*(2 + 1) = 6. Rzeczywiście, współczynniki 6 z 18 są .

Oto mały benchmark między moją metodą a metodą opisaną i opublikowaną przez @Maciej. Jego ma tę zaletę, że jest łatwiejsza do wykonania, natomiast kopalnia ma tę zaletę, że szybciej, jeśli zmiana tylko iterację ciągu liczb, jak Ja wam uczyniłem dla tego testu:

class Program 
{ 
    static private List<int> primes = new List<int>(); 

    private static void Sieve() 
    { 
     bool[] ok = new bool[2000]; 

     for (int i = 2; i < 2000; ++i) // primes up to 2000 (only need up to sqrt of 1 000 000 actually) 
     { 
      if (!ok[i]) 
      { 
       primes.Add(i); 

       for (int j = i; j < 2000; j += i) 
        ok[j] = true; 
      } 
     } 
    } 

    private static int IVlad(int n) 
    { 
     int initial_n = n; 
     int factors = 1; 

     for (int i = 0; primes[i] * primes[i] <= n; ++i) 
     { 
      int power = 0; 
      while (initial_n % primes[i] == 0) 
      { 
       initial_n /= primes[i]; 
       ++power; 
      } 
      factors *= power + 1; 
     } 

     if (initial_n > 1) 
     { 
      factors *= 2; 
     } 

     return factors; 
    } 

    private static int Maciej(int n) 
    { 
     int factors = 1; 
     int i = 2; 
     for (; i * i < n; ++i) 
     { 
      if (n % i == 0) 
      { 
       ++factors; 
      } 
     } 

     factors *= 2; 

     if (i * i == n) 
     { 
      ++factors; 
     } 

     return factors; 
    } 

    static void Main() 
    { 
     Sieve(); 


     Console.WriteLine("Testing equivalence..."); 

     for (int i = 2; i < 1000000; ++i) 
     { 
      if (Maciej(i) != IVlad(i)) 
      { 
       Console.WriteLine("Failed!"); 
       Environment.Exit(1); 
      } 
     } 

     Console.WriteLine("Equivalence confirmed!"); 

     Console.WriteLine("Timing IVlad..."); 
     Stopwatch t = new Stopwatch(); 

     t.Start(); 
     for (int i = 2; i < 1000000; ++i) 
     { 
      IVlad(i); 
     } 

     Console.WriteLine("Total milliseconds: {0}", t.ElapsedMilliseconds); 
     Console.WriteLine("Timing Maciej..."); 

     t.Reset(); 
     t.Start(); 
     for (int i = 2; i < 1000000; ++i) 
     { 
      Maciej(i); 
     } 


     Console.WriteLine("Total milliseconds: {0}", t.ElapsedMilliseconds); 
    } 
} 

wyników na moim komputerze:

Równoważność testowania ...
Równoważność potwierdzona!
Timing IVlad ...
Wszystkich milisekund: 2448
Timing Maciej ...
Wszystkich milisekund: 3951
Naciśnij dowolny klawisz, aby kontynuować. . .

+0

Tak, kluczem jest uświadomienie sobie, że każdy dzielnik ma swój odpowiednik i wystarczy pętla aż do pierwiastka kwadratowego. Jednakże, jeśli tak czy owak puszcza się od 2 do pierwiastka kwadratowego, sprawdzając, czy w każdym przypadku dzielę n, obliczanie mocy i dzielenie n to strata czasu, według mnie. Lepiej po prostu zwiększyć licznik czynników. –

+0

Prawda, jeśli 'i' jest współczynnikiem' n', to tak samo jest 'n/i'. Jest to inny sposób robienia tego, który pozwala przejść tylko do pierwiastka kwadratowego, tylko upewnij się, że 'i' i' n/i' są różne, więc nie liczyć niczego dwa razy!Nie pozwala ci to jednak tylko sprawdzać liczb pierwszych, więc nie sądzę, że jest to zawsze szybsze (dzięki mojej opublikowanej metodzie możesz wstępnie obliczać liczby pierwsze, aby przyspieszyć). Na przykład dla '20', musisz sprawdzić' 4', aby zdać sobie sprawę, że '4' i' 5' są czynnikami opisywanej metody (jeśli myślę o tym samym). – IVlad

4

Dostępnych jest wiele algorytmów - od prostego opracowywania prób do bardzo zaawansowanych algorytmów dla dużych liczb. Spójrz na Integer Factorization na Wikipedii i wybierz taki, który odpowiada Twoim potrzebom.

Oto krótka, ale nieefektywna implementacja C#, która określa liczbę czynników pierwszych. Jeśli potrzebujesz liczby czynników (nie czynników pierwszeństwa), musisz przechowywać czynniki pierwsze z ich licznością i obliczyć liczbę czynników później.

var number = 3 * 3 * 5 * 7 * 11 * 11; 

var numberFactors = 0; 
var currentFactor = 2; 

while (number > 1) 
{ 
    if (number % currentFactor == 0) 
    { 
     number /= currentFactor; 
     numberFactors++; 
    } 
    else 
    { 
     currentFactor++; 
    } 
} 
+0

To jest złe. Co jeszcze liczysz, czynniki czy czynniki pierwsze? Da ci to 3 czynniki za 18, co jest błędne w obu kierunkach. – IVlad

+0

liczba czynników liczy czynniki pierwsze, ale moja odpowiedź wskazuje, że liczba czynników może być uzyskana z czynników pierwszych i ich mnogości. –

+0

Nie masz racji twierdząc, że twoje rozwiązanie liczy czynniki pierwsze! "numberFactors" będzie zawierać wartość "3" dla "18", co jest błędem, w "18" są tylko "2" czynniki pierwsze: "2 i 3". – IVlad

-4

Algorytm Euclida powinien wystarczyć.

+0

-1 Algorytm Euclida nie znajduje faktoryzacji liczby całkowitej. –

+0

Tak, to prawda. jest to algorytm podziału, który z definicji będzie powodował czynniki. Być może powinien był określić faktoryzację PRIME. – joejoeson

1

Oto owoc mojej krótkiej dyskusji z |/| reklamie :)

read given number in n 
int divisorsCount = 1; 
int i; 
for(i = 2; i * i < n; ++i) 
{ 
    if(n % i == 0) 
    { 
     ++divisorsCount; 
    } 
} 
divisorsCount *= 2; 
if(i * i == n) 
{ 
    ++divisorsCount; 
} 
+0

Tak, ale wykonujesz iterację po KAŻDYM numerze, aż do sqrt z 'n'. Moja metoda ma potencjał polegający na iteracji tylko nad liczbami głównymi. Jest to łatwiejsze do wdrożenia, ale prawdopodobnie tylko lepiej, jeśli nie musisz go uruchamiać wiele razy. – IVlad

0

Ostrożnie, ta odpowiedź jest nieprzydatne/szybki dla pojedynczej wartości n.

Metoda 1:

można dostać w czasie O (polylog (n)) jeśli utrzymanie tabelę przeglądową (dla pierwszego głównego czynnika liczbę).

Jeśli gcd (a, b) == 1, to nie. współczynników a * b = (liczba czynników a) * (liczba czynników b)

Dlatego dla danej liczby a * b, jeśli gcd (a, b)! = 1 to może mieć dwie inne liczby p i q, gdzie p = a i q = b/gcd (a, b). Zatem gcd (p, q) == 1. Teraz możemy rekursywnie znaleźć liczbę czynników dla p i q.

To zajmie tylko jakąś małą ilość wysiłków zmierzających do zapewnienia ani p, ani q wynosi 1.

PS: Ta metoda jest również przydatna, gdy musisz znać liczbę czynników wszystkich liczb od 1 do n. Byłaby to kolejność O (nlogn + O (tabela przeglądowa)).

Metoda 2 (nie mam prawa własności do tego.)

Jeśli masz przeglądowej dla pierwszego czynnika głównego aż do n, to możesz wiedzieć, że to wszystkich czynników w czasie O (logn) i w ten sposób znaleźć liczbę czynników z nich.

P.S. Google "Faktoryzacja w logn" dla lepszego wyjaśnienia.

+0

Jeśli używasz systemu Linux, zawsze możesz użyć polecenia "factor ", aby uzyskać wszystkie czynniki pierwsze. #Brak kodu – Ajay

Powiązane problemy