Bu soruyu Eratosthenesin elegini (Sieve of Eratosthenes) kullanarak cozdum.
Bu algoritma bize n e kadar olan asal sayilari verir. Kisaca soyle isler,
2 den N e kadar olan sayilari yaz
isaretlenmemis sayi kalmayana kadar:
isaretlenmemis en kucuk sayiyi bul
asallara ekle
katlarini isaretle
Eratosthenesin elegi O(n) hafiza ve O(nloglogn) islem gerektirir. n elemani da isaretleyebilmemiz gerektigi icin O(n) hafiza gerekir. Islem sayisi ise asallarin terslerinin toplaminin ust sinirindan gelmektedir.
Asallari bulduktan sonra en buyuk asaldan en kucuk asala dogru bolme kontrol ederek istenilen sonuc elde edilebilir. Asagida Bunu hesaplayan C kodunu paylastim. Bu kod icin daha onceden su soruda acikladigimiz Liste veri yapisini asallari saklamak icin kullandim.
#include <stdlib.h>
#include <stdio.h>
#include "linked_list.h"
long int
sifir_bul (long int limit, char *sayilar, int baslama_indeksi)
{
int ret = -1;
for (long int ctr = baslama_indeksi; ctr < limit; ctr++)
{
if (sayilar[ctr] == 0)
{
ret = ctr;
break;
}
}
return ret;
}
void
asallari_bul (Liste * asallar, long int limit)
{
char *sayilar = calloc (limit, sizeof (char));
if (sayilar == NULL)
{
printf ("alloke edemedi kapaniyorum");
exit (0);
}
long int indeks = 0;
while (indeks != -1)
{
long int asal = indeks + 2;
basa_eleman_ekle (asallar, asal);
for (long int temp = indeks; temp < limit; temp = temp + asal)
{
sayilar[temp] = 1;
}
indeks = sifir_bul (limit, sayilar, indeks);
}
free (sayilar);
}
int
main ()
{
Liste asallar;
asallar.ilk_eleman = NULL;
asallar.son_eleman = NULL;
asallar.eleman_sayisi = 0;
long int n = 600851475143;
long int sqrt_n = 775147;
asallari_bul (&asallar, sqrt_n);
Eleman *e = asallar.ilk_eleman;
while (e != NULL)
{
if (n % e->veri == 0)
{
printf ("%ld, %ld yi boler \n", e->veri, n);
}
e = e->adres;
}
}