Listen Sie primfaktorisierte natürliche Zahlen bis zu N in aufsteigender Reihenfolge auf

8

Für eine gegebene nListe Primfaktorisierung aller natürlichen Zahlen zwischen 1und nin aufsteigender Reihenfolge. Für n= 10 wäre die Ausgabe beispielsweise:

1:
2: 2^1
3: 3^1
4: 2^2
5: 5^1
6: 2^1 3^1
7: 7^1
8: 2^3
9: 3^2
10: 2^1 5^1

Bedarf:

  • Sie können nicht einfach über die Zahlen iterieren und jede von ihnen faktorisieren. (Es sei denn, Sie wissen, wie man eine Zahl in der logarithmischen Zeit berücksichtigt, und dann bezweifle ich, dass Sie Ihre Zeit damit verschwenden würden, Rätsel zu lösen.) Dies ist zu ineffizient.
  • Die Ausgabe sollte wie im obigen Beispiel sein: In jeder Zeile die Zahl und die Liste der Primfaktoren.
  • Bedenken Sie, dass ndies sehr groß sein kann, sodass es möglicherweise nicht möglich ist, alle Faktorisierungen im Speicher zu generieren und sie am Ende zu sortieren. (Aber wenn Sie eine clevere Lösung haben, die dies verletzt, posten Sie sie auch.)
Petr Pudlák
quelle

Antworten:

4

C ++

Implementiert ein Sieb mit Primzahlen bis zu sqrt(n). Verwaltet eine Liste verknüpfter Listen, um zu verfolgen, welche Primzahlen welche kommenden Zahlen teilen. Jedes Mal, wenn eine Primzahl pverwendet wird, wird ihre FactorStruktur um pSlots in der Liste verschoben .

Die meiste Zeit wird damit verbracht, nur printfdie Antwort zu finden.

#include <stdio.h>
#include <stdlib.h>

// lists of Factors represent known prime factors of a number                                                                                              
struct Factor {
  Factor(int p) : prime(p), next(NULL) { }
  int prime;
  Factor *next;
};

int main(int argc, char *argv[]) {
  long long n = atoll(argv[1]);

  // figure out the maximum prime we need to sieve with                                                                                                    
  int maxp = 1;
  while ((long long)maxp * maxp < n) maxp++;
  maxp--;

  // find next power of two up from that for our circular buffer size                                                                                      
  int size = 1;
  while (size < maxp) size *= 2;
  int mask = size - 1;

  // allocate circular buffer of lists of sieving prime factors for upcoming numbers                                                                       
  Factor **factors = new Factor*[size]();

  printf("1:\n");

  for (long long x = 2; x < n; x++) {
    Factor *list = factors[x & mask];
    factors[x & mask] = NULL; // reset so it can hold the list for x + size                                                                                

    if (!list && x <= maxp) { // x is a prime we need to sieve with - make new list with just itself                                                       
      list = new Factor(x);
    }

    // print factor list, push each Factor along to the next list.                                                                                         
    printf("%lld:", x);
    long long y = x;
    while (list) {
      Factor *f = list;
      list = f->next;
      int p = f->prime;

      // count how many factors of p are in x                                                                                                              
      int k = 1;
      y /= p;
      while (y % p == 0) {
        k++;
        y /= p;
      }
      printf(" %d^%d", p, k);

      // splice f into the list for the next number it divides                                                                                             
      long long z = x + f->prime;
      f->next = factors[z & mask];
      factors[z & mask] = f;
    }
    // remaining part of x must be prime                                                                                                                   
    if (y != 1) printf(" %lld^1", y);
    printf("\n");
  }
}
Keith Randall
quelle
4

Unten ist mein Versuch im R5RS-Schema (Haftungsausschluss: Ich bin (noch!) Kein Schemer, also verzeihen Sie den (wahrscheinlich) schrecklichen Code).

(define count 10)

; `factors` is our vector of linked-lists of factors.  We're adding to these
; as we go on.
(define factors (make-vector count 'not-found))
(vector-set! factors 0 '())

; `primes-so-far` contains all the prime numbers we've discovered thus far.
; We use this list to speed up the dividing of numbers.
;   `primes-so-far-last` is a ref to the last entry in the `primes-so-far`
; list, for O(1) appending to the list.
(define primes-so-far '(dummy))
(define primes-so-far-last primes-so-far)

;; Helpers
(define (factor-ref n)
  (vector-ref factors (- n 1)))

(define (factor-cached? n)
  (not (eq? (vector-ref factors (- n 1)) 'not-found)))

(define (factor-put n factor)
  (let* ((rest        (/ n factor))
         (factor-cell (cons factor (factor-ref rest))))
    (vector-set! factors (- n 1) factor-cell)
    factor-cell))

(define (prime-append n)
  (let ((new-prime-cell (cons n '())))
    (set-cdr! primes-so-far-last new-prime-cell)
    (set!     primes-so-far-last new-prime-cell)
    new-prime-cell))

;; The factor procedure (assumes that `[1..n-1]` have already been factorized).
(define (factor n)
  (define (divides? m n)
    (= (modulo n m) 0))

  ; n       the number to factor.
  ; primes  the list of primes to try to divide with.
  (define (iter n primes)
    (cond ((factor-cached? n)
           (factor-ref n))

          ((null? primes)
           ; no primes left to divide with; n is prime.
           (prime-append n)
           (factor-put n n)) ; the only prime factor in a prime is itself

          ((divides? (car primes) n)
           (factor-put n (car primes))
           (factor-ref n))

          (else
           (iter n (cdr primes)))))

  (iter n (cdr primes-so-far)))

(define (print-loop i)
  (if (<= i count)
      (begin
        (display i)
        (display ": ")
        (display (factor i))
        (newline)
        (print-loop (+ i 1)))))

(print-loop 1)

Druckt als:

1: ()
2: (2)
3: (3)
4: (2 2)
5: (5)
6: (2 3)
7: (7)
8: (2 2 2)
9: (3 3)
10: (2 5)

(Nicht genau wie in der Aufgabenbeschreibung, aber alles, was Sie tun müssen, um diese Ausgabe zu erhalten, ist, die Liste zu falten und Wiederholungen derselben Nummer während des Ausgabeteils des Codes zusammenzuführen. Die interne Darstellung / der interne Algorithmus wäre immer noch das Gleiche.)

Die Idee ist, die zuvor berechneten Werte zwischenzuspeichern, aber die Tatsache zu nutzen, dass die Faktoren von nder erste Primfaktor von nund die Primfaktoren von (n / erster Faktor) sind. Letzteres ist jedoch bereits bekannt, sodass wir die bereits vorhandene Liste von Faktoren für diese kleinere Anzahl erneut verwenden. Somit wird für jede Zahl, in [1..n]der es sich nicht um eine Primzahl handelt, eine einzelne Nachteilezelle gespeichert.

Für jede Nummer wird eine einzelne Cons-Zelle erstellt und gespeichert. Daher sollte dieser Ansatz mit der O(n)Speichernutzung ausgeführt werden. Ich habe keine Ahnung, ob es möglich ist, die zeitliche Komplexität sauber auszudrücken.

FireFly
quelle
0

C (gcc)

#include <stdio.h>
#include <stdlib.h>

#define true 1
#define false 0

int square(int a){
	return a * a;
}

void prime_factors(int n){
	// this is an array of n elements, which will contain all found primes.
	// curprime stores the index of the last found prime, which saves us searching for where to insert the next one and things.
	int* primes = calloc(sizeof(int), n);
	int curprime = 0;

	printf("1:\n"); // Micro optimization, and rids me of the messing around that is 1.
	for(int i=2; i<=n; i++){
		// Print the current i.
		printf("%i: ",i);

		// Define val, which we'll slowly make smaller and smaller. Mwahaha.
		int val = i;
		int isprime = true;	// This will be set to false if it's divisible by any primes, which of course, means it's also not a prime.

		// Loop through primes, this loop stops if we've reached either more than sqrt(count) primes, or val is equal to zero (as such, it's fully prime factorized).
		for(int*prime_pointer = primes; val && square((int)(prime_pointer-primes)) < curprime; prime_pointer++){
			int prime = *prime_pointer;
			// if the current val is divisible by the current prime.
			while(val%prime == 0){
				isprime = false; 	// We know that this number isn't prime.
				val = val / prime;	// Divide val by it.
				printf("%i ",prime);// And write this prime.
			}
		}
		if(isprime){	// If this number is a prime.
			printf("%i ",i);	// Append it to its own list.
			primes[curprime++] = i;	// And append this new prime to our list of primes.
		}
		printf("\n");	// Terminate the line with a newline. Duh...
	}
}

int main(int argc, char** argv){
	prime_factors(1000);
}

Definiert die Funktion, prime_factorsdie eine Ganzzahl akzeptiert nund über printf im folgenden Format ausgibt:

1:
2: 2 
3: 3 
4: 2 2 
5: 5 
6: 2 3 
7: 7 
8: 2 2 2 
9: 3 3 
10: 2 

Dies verwendet O (n) zusätzlichen Speicher, und ich bin mir nicht sicher, wie zeitlich komplex.

Probieren Sie es online aus!

Ein Taco
quelle