我认为这里不需要线程,如果数字的平方和等于 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)。
上面的代码需要 435 才能得到所有低于 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,
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