わかりました、あなたのプログラムは予想よりも長くかかっています。まず、無限ループに陥っているのか、単に遅いのかを調べます。そのために、メインループに以下を追加して、プログラムに進行状況を出力させましょう。
int statesVisited = 0;
while (OPEN.empty() == false && STATE == false) {
statesVisited++;
System.out.println(statesVisited);
次に、プログラムが 1 秒あたり数千の州を訪問したことがわかります。私たちのプロセッサは毎秒数十億の命令を実行するため、これは状態の処理に約百万の CPU 命令が必要であることを意味します。そんなに高くないはずですよね?では、何が原因でしょうか?
一般的に言えば、プロファイラーを使用して、コードのどの部分にこの時間が費やされているかを測定しますが、プログラムが非常に短いため、最初に推測してみることができます。私が最初に推測するのは、私たちが訪れたすべての州を印刷するには、かなりの費用がかかる可能性があるということです。これを確認するために、1000 番目ごとの状態だけを出力してみましょう。
while (OPEN.empty() == false && STATE == false) {
statesVisited++;
if (statesVisited % 1000 == 0) {
System.out.println(statesVisited);
}
場所を変えると、最初の 5000 州が 2 秒未満で訪問されていることがわかります。そのため、印刷は確かに重要でした。また、興味深いことにも気付きました。最初の 5000 州は 1 秒以内に訪問されますが、何らかの理由で、プログラムはどんどん遅くなっていくようです。20000 州を訪問した時点で、1000 州を訪問するのに約 1 秒かかり、悪化し続けています。状態の処理がますます高価になるべきではないため、これは予期しないことです。したがって、ループ内の一部の操作がますます高価になっていることがわかります。コードを見直して、それがどの操作であるかを特定しましょう。
コレクションのサイズに関係なく、プッシュとポップには一定の時間がかかります。ただし、Stack.search と LinkedList.contains も使用します。これらの操作は両方とも、スタックまたはリスト全体を反復処理する必要があることが文書化されています。それでは、これらのコレクションのサイズを出力しましょう。
if (statesVisited % 1000 == 0) {
System.out.println(statesVisited);
System.out.println(OPEN.size());
System.out.println(CLOSED.size());
System.out.println();
}
しばらく待つと、次のようになります。
40000
25947
39999
したがって、OPEN には 25000 の要素が含まれ、CLOSED には約 40000 の要素が含まれます。これが、状態の処理がますます遅くなる理由を説明しています。java.util.HashSet
したがって、 orなどのより効率的な contains 操作を使用するデータ構造を選択する必要がありますjava.util.LinkedHashSet
(これはハッシュ セットとリンク リストのハイブリッドであり、追加された順序で要素を取得できます)。これを行うと、次のようになります。
public static LinkedHashSet<String> OPEN = new LinkedHashSet<String>();
public static HashSet<String> CLOSED = new HashSet<String>();
public static boolean STATE = false;
public static void main(String args[]) {
int statesVisited = 0;
String start = "123804765";
String goal = "281043765";
String X = "";
String temp = "";
OPEN.add(start);
while (OPEN.isEmpty() == false && STATE == false) {
X = OPEN.iterator().next();
OPEN.remove(X);
int pos = X.indexOf('0'); // get position of ZERO or EMPTY SPACE
if (X.equals(goal)) {
System.out.println("SUCCESS");
STATE = true;
} else {
// generate children
CLOSED.add(X);
temp = up(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = left(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = down(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = right(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
}
}
}
/*
* MOVEMENT UP
*/
public static String up(String s, int p) {
String str = s;
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 3)) + '0' + newS.substring(p - 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT DOWN
*/
public static String down(String s, int p) {
String str = s;
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 3)) + '0' + newS.substring(p + 4);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT LEFT
*/
public static String left(String s, int p) {
String str = s;
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 1)) + '0' + newS.substring(p);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT RIGHT
*/
public static String right(String s, int p) {
String str = s;
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 1)) + '0' + newS.substring(p + 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
public static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
ほぼ瞬時に「成功」を出力します。