Работая над проектом класса, я заметил очень странную ошибку в моей системе.
Приведенный ниже код читает словарь доступных слов, и алгоритм DFS пытается найти маршрут от одного слова к другому слову, учитывая график слов (график строится, если есть грань отна b, если a отличается только одной буквой от b).
При выполнении моего кода по умолчанию (с RUN_DO_NOTHING_BLOCK = false) я всегда переполняюсь стеком на каждом устройстве. При запуске кода с RUN_DO_NOTHING_BLOCK = true это как-то решает проблему переполнения стека, и код работает отлично. Проблема в том, что RUN_DO_NOTHING_BLOCK буквально ничего не делает в коде.
Ввод, который нам небезразличен, - "смерть опухоли \ n" (эти два слова не связаны и заставляют DFSдля поиска во всей связанной области «смерти». Примером подключенного ввода является «death chops \ n».
Вот словарь, в котором читается код: dictionary.txt
Я знаю, что ошибки переполнения стека сильно зависят от размера, выделенного для стека вызовов и кучи, и отличаются от компьютера к компьютеру, но я заметил эту ошибку на каждом устройстве, на котором я запускал этот код, и я думаю, что вы сможетеСоздайте его заново. Причина, по которой я написал это, заключается в том, что я хочу знать, почему бесполезный код решил эту проблему.
import java.util.*;
import java.io.*;
public class Main {
public static Set<String> dictionary;
/**
* The graph created from the dictionary.
* Maps from a node to a set of edges connected to the node.
*/
public static Map<String,Set<String>> graph;
public static final boolean RUN_DO_NOTHING_BLOCK = false;
public static void main(String[] args) {
//initalization
dictionary = makeDictionary();
graph = createGraph(dictionary);
Scanner scan = new Scanner(System.in);
String startWord = scan.next(), endWord = scan.next();
ArrayList<String> wordLadder = getWordLadderDFS(startWord, endWord);
System.out.println(wordLadder);
}
public static ArrayList<String> getWordLadderDFS(String start, String end) {
start = start.toUpperCase();
end = end.toUpperCase();
//the actual ladder
ArrayList<String> ladder = new ArrayList<>();
//all unvisited nodes
Set<String> unVisitedNodes = new HashSet<>();
unVisitedNodes.addAll(dictionary);
//start the recursive search
boolean found = getWordLadderDFSRecurse(start, end, unVisitedNodes, ladder);
return ladder;
}
private static boolean getWordLadderDFSRecurse(String node, String end, Set<String> unVisitedNodes, ArrayList<String> ladder) {
//if already visited this node then dont do anything
if(node==null || !unVisitedNodes.contains(node)){
return false;
}
ladder.add(node);
if(node.equals(end)){
return true;
}
unVisitedNodes.remove(node);
//*************
//THIS IS THE DO NOTHING BLOCK...
if(RUN_DO_NOTHING_BLOCK) {
for (String i : unVisitedNodes) {
if (unVisitedNodes.contains(node)) {
unVisitedNodes.remove(node);
}
}
}
//**************
//recurse deeper
Set<String> neighbors = graph.get(node);
//go through all neighbors and try to recurse into them
//go through neighbors in order though, from most promising to least
for (String neighbor : neighbors) {
//go in
boolean found = getWordLadderDFSRecurse(neighbor, end, unVisitedNodes, ladder);
//if we found a path then return
if (found) {
return true;
}
}
//not found
ladder.remove(node);
return false;
}
/**
* Creates the graph from the given dictionary of words.
* @param dictionary
* @return the graph in the form of an adjacency list.
*/
private static Map<String, Set<String>> createGraph(Set<String> dictionary){
Map<String, Set<String>> graph = new HashMap<>();
for(String word: dictionary) {
graph.put(word, new HashSet<>());
}
/**
* Building from all possible one letter deviance of a given word is faster than looping through a huge dictionary again
*/
for(String word1: dictionary){
StringBuilder stringBuilder = new StringBuilder(word1);
for(int i=0;i<word1.length();i++){
for(char c='A'; c<='Z';c++) {
if(c==word1.charAt(i)){
continue;
}
stringBuilder.setCharAt(i, c);
if(dictionary.contains(stringBuilder.toString())){
graph.get(word1).add(stringBuilder.toString());
}
}
stringBuilder.setCharAt(i,word1.charAt(i));
}
}
return graph;
}
public static Set<String> makeDictionary () {
Set<String> words = new HashSet<String>();
try {
Scanner infile = new Scanner(new File("dictionary.txt"));
while (infile.hasNext()) {
words.add(infile.next().toUpperCase());
}
}catch(Exception e){
throw new RuntimeException(e);
}
return words;
}
}