Nまでの素因数分解自然数を昇順でリストします


8

与えられたnリストに対して、昇順および昇順のすべての自然数の素因数分解。たとえば、= 10の場合、出力は次のようになります。1nn

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

要件:

  • 数値を繰り返し処理して、それぞれを因数分解することはできません。(数値を対数時間で因数分解する方法を知らない限り、パズルを解くのに時間を無駄にすることはないと思います。)これは非効率的です。
  • 出力は上記の例のようになります。各行に、数とその素因数のリスト。
  • これn非常に大きくなる可能性があるため、すべての因数分解をメモリに生成し、最後にそれらを並べ替えることは不可能である可能性があることを考慮してください。(ただし、これに違反する賢い解決策がある場合は、それも投稿してください。)

回答:


4

C ++

までの素数を使用してふるいを実装しsqrt(n)ます。リンクされたリストのリストを維持して、どの素数が次の数を分割するかを追跡します。素数pが使用されるたびに、そのFactor構造はpリストの下のスロットに移動されます。

ほとんどの時間はprintf答えを出すだけに費やされます。

#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");
  }
}

4

以下は、R5RSスキームでの私の試みです(免責事項:私は実際にはSchemerではないので、(恐らく)恐ろしいコードを許してください)。

(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)

として印刷:

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)

(タスクの説明とまったく同じではありませんが、その出力を取得するために必要なことは、コードの出力部分で、リストを折りたたみ、同じ数の繰り返しをマージすることだけです。内部表現/アルゴリズムは、同じ。)

アイデアは、以前に計算された値をキャッシュすることですが、の因子nがの最初の素因数nと(n /第一因子)の素因数であることを利用します。しかし、後者は既に知られているので、その少数のために既存の因子のリストを再利用します。したがって、[1..n]素数でない各数値に対して、単一のコンスセルが格納されます。

番号ごとに、1つのコンスセルが作成され、保存されます。したがって、このアプローチはO(n)ストレージを使用して実行する必要があります。時間の複雑さをきちんと表現できるかどうかはわかりません。


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);
}

prime_factors整数nを受け取り、printfを介して次の形式で出力する関数を定義します。

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

これはO(n)の追加メモリを使用し、時間の複雑さはわかりません。

オンラインでお試しください!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.