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(n\log\log n)$ 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)
{ // baslama indeksinden itibaren bir dizinin icinde ilk sifiri verir isaretlenmis sayiyi bulmak icin fonksiyon
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)); // bir tane dizi olustur dizinin n indeksindeki deger bize n-2 nin asal olup olmayacagini soyleyecek
if (sayilar == NULL)
{
printf ("alloke edemedi kapaniyorum");
exit (0);
}
long int indeks = 0;
while (indeks != -1)
{ // isaretlenmemis sayi kalmayana kadar yap
//printf("indeks : %d \n",indeks);
long int asal = indeks + 2; //
basa_eleman_ekle (asallar, asal); // sayiyi asallar listesine ekle
for (long int temp = indeks; temp < limit; temp = temp + asal)
{
sayilar[temp] = 1; // sayiyinin kaylarini isaretle
}
indeks = sifir_bul (limit, sayilar, indeks); // isaretlenmemis ilk sayiyi bul
}
free (sayilar); // sayilar dizisine iihtiyacimiz kalmadi yokedebiliriz
}
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;
}
}