ここでスレッド化する必要はないと思います。数字の 2 乗の合計が 1 に等しい場合、幸せな数は幸せです。シーケンスに既にテスト済みの数値が含まれている場合。終了するだけです。
ウィキペディアから
n が幸せでない場合、その数列は 1 にはなりません。代わりに、循環に陥ります。
public class Happy_numbers {
static int[]SQUARES={0,1,4,9,16,25,36,49,64,81};
public static boolean is_happy(int n){
return is_happy(n, new HashSet<Integer>());
}
public static boolean is_happy(int n, Collection<Integer> sofar){
if(n==1) return true;
else if(sofar.contains(n)) return false;
sofar.add(n);
if(n<10) {
return is_happy(SQUARES[n], sofar);
}
char[]digits=String.format("%s", n).toCharArray();
int s = 0;
for(char c:digits){
s+= SQUARES[Integer.valueOf(String.format("%s", c))];
}
return is_happy(s, sofar);
}
public static void main(String[]args){
Collection<Integer> c1 = Arrays.asList(
1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97,
100, 103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208,
219, 226, 230, 236, 239, 262, 263, 280, 291, 293, 301, 302, 310, 313, 319,
320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 379, 383, 386, 391,
392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496 );
Collection<Integer> c2 = new ArrayList<Integer>(c1.size());
long t = System.currentTimeMillis();
int c = 1;
for(int i=0;i<500;i++){
if(is_happy(i)) {
System.out.print(i+", ");
if(c++ % 20 == 0) System.out.println();
c2.add(i);
}
}
t = System.currentTimeMillis()-t;
System.out.println("\nTIME : " + t);
System.out.println("Got them all < 500 : " + (c2.containsAll(c1) && c1.containsAll(c2)));
}
}
また、マップやキャッシュ技術を使用してさらに改善することもできるため、数値が適切で、以前にこの数値を計算したことがある場合は、同じことを再度行う必要はありません。ウィキペディアより、
500未満のハッピーナンバーは、1、7、10、13、19、23、28、31、32、44、49、68、70、79、82、86、91、94、97、100、103、109です。 , 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262, 263, 280, 291, 293, 301, 302, 310 , 313, 319, 320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 379, 383, 386, 391, 392, 397, 404, 409, 440, 446, 464, 469 、478、487、490、496 (OEIS のシーケンス A007770)。
上記のコードでは、500 未満のすべてのハッピー ナンバーを取得するには 435 が必要です。
1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100,
103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262,
263, 280, 291, 293, 301, 302, 310, 313, 319, 320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376,
379, 383, 386, 391, 392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496,
TIME : 435
Got them all < 500 : true
そのため、少なくとも現在の数値について、これまでに計算されたものを記憶できるように、コードにいくつかの変更を加えました。
public class Happy_numbers {
static class Ishappy extends Thread {
private Integer num;
private Thread main;
private volatile boolean out = false;
private boolean unhappy = false;
Ishappy(int i, Thread main) {
this.main = main;
num = i;
}
public boolean isUnhappy() {
return unhappy;
}
void Exit() {
out = true;
}
@Override
public void run() {
Set<Integer> sofar = new HashSet<Integer>();
while(!out && num != 1) {
unhappy = sofar.contains(num);
if(num == 1 || unhappy) {
main.interrupt();
break;
}
sofar.add(num);
String s = num.toString();
int temp = 0;
for(int i = 0 ; i < s.length(); i++) {
int x = Integer.parseInt(s.substring(i, i+1));
temp += x*x;
}
num = temp;
}
}
}
public static void main(String[] args) throws Exception{
byte path[] = null;
String s = "./data.txt";
FileInputStream fin = new FileInputStream(s);
InputStreamReader in = new InputStreamReader(fin);
BufferedReader br = new BufferedReader(in);
int num;
while((s = br.readLine()) != null) {
num = Integer.parseInt(s);
Ishappy ishappy = new Ishappy(num,Thread.currentThread());
ishappy.start();
ishappy.join();
if(ishappy.isUnhappy()){
System.out.println("Number ["+num+"] is not happy");
}else{
System.out.println("Number ["+num+"] is happy");
}
}
br.close();
in.close();
fin.close();
}
}
そして出力は
Number [1] is happy
Number [7] is happy
Number [22] is not happy
編集
メインスレッドが中断されない理由がわかりました。
メインの while ループでは、num が 1 であるかどうかを確認します。1 の場合は、num の値をチェックし、それに基づいてメイン スレッドを中断する if 条件に到達しません。
public class Happy_numbers {
public static void main(String[] args) throws IOException{
String s = "./data.txt";
FileInputStream fin = new FileInputStream(s);
InputStreamReader in = new InputStreamReader(fin);
BufferedReader br = new BufferedReader(in);
int num;
while((s = br.readLine()) != null) {
num = Integer.parseInt(s);
Ishappy ishappy = new Ishappy(num,Thread.currentThread());
ishappy.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println(1);
continue; // here is another problem, infinit loop
}
if(ishappy.isAlive()) {
ishappy.Exit();
System.out.println(0);
} else
System.out.println(11);
}
br.close();
in.close();
fin.close();
System.out.println("DONE");
}
}
ここにIhappyクラスがあります
class Ishappy extends Thread {
private volatile Integer num;
private Thread main;
private volatile boolean out = false;
Ishappy(int i, Thread main) {
this.main = main;
num = i;
}
void Exit() {
out = true;
}
@Override
public void run() {
while(!out) { /// <- here was the problem
if(num.intValue() == 1) { // since this condition will break out
main.interrupt(); // of the loop, you do not need it in the
break; // while condition
}
String s = num.toString();
int temp = 0;
for(int i = 0 ; i < s.length(); i++) {
int x = Integer.parseInt(s.substring(i, i+1));
temp += x*x;
}
num = temp;
}
}
}
そして出力は
1
1
0
DONE