如何生成可以连接到新素数的素数对列表?

时间:2015-08-13 21:13:24

标签: scheme

我有一个存储在变量primes-list-split中的素数列表,这些素数以number->list方法以列表格式表示。格式如下:2,3,5,7和11的主要列表为'((2) (3) (5) (7) (1 1))

get-prime-pairs将此列表作为输入,并尝试查找连接到另一个素数的每个组合。然后它应该在列表表示的列表中返回这些对。所以连接到3367的对3 367也应该在表示的列表中((3)(3 6 7))。

为了达到这个目的,我的想法是遍历列表,并且每个表示为列表的素数都将其与表示为列表的所有其他素数相连接。如果在通过list->number方法转换为数字后组合列表表示也是素数,我将其添加到返回的最终列表中。

代码实现如下:

(define (prime? n)
  (define (check-divisible n divisor)
    (cond ((= divisor 1) #t)
          ((= 0 (modulo n divisor)) #f)
          (else (check-divisible n (- divisor 1)))))
  (cond ((<= n 1) #f)
        ((= n 2) #t)
        ((even? n) #f)
        (else (check-divisible n (truncate (sqrt n))))))

; Copyright (C) 2011 Toby Thain, toby@telegraphics.com.au
(define (primes-up-to n)
  (let ((sieve (make-vector (+ n 1) #t)))
    (define (test-prime i)
      (define (is-prime? idx)
        (vector-ref sieve idx))
      (define (not-prime! idx)
        (vector-set! sieve idx #f))
      (define (remove-multiples i step)
        (when (<= i n)
          (not-prime! i)
          (remove-multiples (+ i step) step)))
      (if (> i n)
          '()
          (if (is-prime? i)
              (begin
                (remove-multiples i i)
                (cons i (test-prime (+ i 1))))
              (test-prime (+ i 1)))))
    (test-prime 2)))

(define primes-list (primes-up-to 100000))


;; From list generate split arrays of allowed pairs

; www.stackoverflow.com/questions/12834562/scheme-number-to-list#12841962
(define (number->list n)
  (let loop ((n n) (acc '()))
    (if (< n 10)
        (cons n acc)
        (loop (quotient n 10)
              (cons (remainder n 10) acc)))))

; www.stackoverflow.com/questions/1683479/how-to-convert-a-list-to-num-in-scheme#1688960
(define (list->number lst)
  (let loop ((n 0) (lst lst))
    (if (empty? lst)
        n
        (loop (+ (* 10 n) (car lst)) (cdr lst)))))

; http://stackoverflow.com/questions/31909685/how-can-i-filter-null-values-from-this-list
(define primes-list-split 
  (map number->list primes-list))

(define (get-prime-pairs lst)
  (define (split lst pos)
    (list (drop-right lst pos) (take-right lst pos)))
  (define (get-prime-pairs-iter n acc)
    (if (zero? n) 
        (if 
         (or (null? acc) 
             ; filter out those values that start with leading zero
             (zero? (caar acc)) 
             (zero? (caadr acc))) 
         '() 
         (list acc))
        (get-prime-pairs-iter 
         (- n 1) 
         (let ((s (split lst n)))
           (if (and (prime? (list->number (car s)))
                    (prime? (list->number (cadr s))))
               (append s acc)
               acc)))))
  (get-prime-pairs-iter (- (length lst) 1) '()))

(define split-array-of-allowed-pairs 
  (append-map get-prime-pairs primes-list-split))

split-array-of-allowed-pairs 

不幸的是,有时它会返回包含四个或更多值的“对”。例如,split-array-of-allowed-pairs包含如下对:

((...)
((3) (6 4 3))
((3) (6 5 9))
((3 6 7) (3) (3) (6 7 3))
((3 6 7) (7) (3) (6 7 7))
(...))

我们在这里看到返回更长的组合。我希望((3 6 7) (3))((3) (3 6 7))分别以两对的形式分别表示。不知怎的,他们最终结合起来了。

我的方法有什么问题,有谁知道我怎么解决它?

提前致谢。

请参阅此处的要点以获取下面两个测试的代码,这两个测试都应返回true:https://gist.github.com/erooijak/2d462ad429e6e05ddd25

2 个答案:

答案 0 :(得分:2)

您的功能get-prime-pairs有几个问题。这是一个有效的非尾递归版本:

(define (get-prime-pairs lst)
  (define (find-all-prime-pairs prime lst)
    (if (null? lst)
        '()
        (if (prime? (list->number (append prime (car lst))))
            (cons (list prime (car lst))
                  (find-all-prime-pairs prime (cdr lst)))
            (find-all-prime-pairs prime (cdr lst)))))
  (append-map (lambda (x) (find-all-prime-pairs x lst)) lst))

(define split-array-of-allowed-pairs (get-prime-pairs primes-list-split))

以下是它的工作原理。

函数get-prime-pairs通过调用函数lst来尝试列表find-all-prime-pairs的所有元素将它们与列表的所有元素组合在一起。

辅助函数find-all-prime-pairs尝试将其第一个参数(prime)与列表第二个参数(lst)的所有元素组合在一起,并返回组合所在的所有对素数。在这种情况下,递归在第二个参数lst上:如果它是空的,则找不到对,否则它会prime追加到car lst看看这是否是素数。如果这是真的,那么该函数返回第一对获得的列表和递归调用的结果lst的其余部分,否则它只返回递归调用的结果。

在我看来,你的递归不起作用的主要问题是在第一次尝试时将递归函数写为尾递归并不是使其正确的最佳方法。所以,我敢建议你考虑编程的基本规则:

  

首先,让您的程序工作,然后,如果有必要,使其有效。

换句话说,我建议你首先将函数写为“正常”递归函数,然后,当你确定它有效时,如果需要,将其重写为尾递归(或迭代)(在上面)这是一个练习)。

作为最后的注释,请考虑3367不是素数,等于7 * 13 * 37.

答案 1 :(得分:-1)

public class PrimeConcatenation {
    public static void main(String[] args) {
        Scanner s1=new  Scanner(System.in);
        int num =s1.nextInt();
        int[] arr=new int[num];
        int[] res;
        int index=0;
        int count=0;
        for (int i = 2; i <=num; i++) {            
            if(prime(i))
            {
                arr[index]=i;
                index++;
//              System.out.println(""+i+""+prime(i));  
            }            
        }
        res=new int[index*index];
        int res_index=0;        
        for(int i=0;i<index;i++)
        {
            for(int j=0;j<index;j++)
            {
                String str=""+arr[i]+arr[j];
                if(prime(Integer.parseInt(str)))
                {
//                    System.out.println("val is "+str);
                    res[res_index]=Integer.parseInt(str);
                    res_index++;
                    count++;
                }                
            }
        }
        System.out.println(""+count);        
    }
    static boolean prime(int num)
    {
        boolean res;
        for(int i=2;i<num;i++)
        {
            if(num%i==0)
            {
                res=false;
                return res;
            }            
        }
        return true;
    }   
}