Ссылка на экземпляр, который ссылается на экземпляр

#java #class #hashmap #instance

Вопрос:

Я не уверен, что название этого вопроса правильное.

У меня есть школьное задание, где мы должны создать два класса.

В одном классе мы определяем отношения между людьми, например, A знает B, а в другом классе мы задаем вопросы об этом, например, знает ли A B?

Первый класс ниже определяет отношения и предоставляет методы, второй класс запрашивает о них.

Я уверен, что моя ошибка кроется где-то в общедоступном логическом «knowsWithDegree». Вы в состоянии помочь?

 public class SocialGraph {

    private HashMap<String, List<String>> map = new HashMap<String, List<String>>();
    
    public SocialGraph() {   // empty constructor
        map = new HashMap<String, List<String>>();
    }
    
    public void addIndividual(String a) {
        if (!map.containsKey(a)) {
            map.put(a, new ArrayList<String>());
        } else {
    
        }
    }
    
    public boolean hasKnowsArrow(String a, String b) {
        if (map.containsKey(a)) {
            return map.get(a).contains(b);
        } else {
            return false;
        }
    }
    
    public void addKnowsArrow(String a, String b) {
    
        if ((!map.containsKey(a) || !map.containsKey(b)) || (hasKnowsArrow(a, b))) {
        } else {
            map.get(a).add(b);
        }
    }
    
    public void removeKnowsArrow(String a, String b) {
    
        if ((!map.containsKey(a) || !map.containsKey(b)) || (!hasKnowsArrow(a, b))) {
        } else {
            map.get(a).remove(b);
        }
    }
    
    public boolean knowsWithDegree(String a, String b, int x) {
        Object[] keys = map.keySet().toArray();
    
        int y;
        y = 0;
    
        if (map.get(a).contains(b)) {
            y = 1;
        } else {
    
            if ((map.get(a).contains(map.get(keys[0]).contains(b))) || (map.get(a).contains(map.get(keys[1]).contains(b))) ||
                    (map.get(a).contains(map.get(keys[2]).contains(b))) || (map.get(a).contains(map.get(keys[3]).contains(b)))) {
                y = 2;
            }
        }
        if (x == y) {
            return true;
        } else
            return false;
        }
    }
    
    
    public class SocialGraphTest {
    
        public static void main(String[] args) {
            SocialGraph socialGraph = new SocialGraph();
            socialGraph.addIndividual("Anne");
            socialGraph.addIndividual("Daisy");
            socialGraph.addIndividual("Bob");
            socialGraph.addIndividual("Charlie");
        
        
            socialGraph.addKnowsArrow("Anne", "Bob");
            socialGraph.addKnowsArrow("Anne", "Daisy");
            socialGraph.addKnowsArrow("Bob", "Daisy");
            socialGraph.addKnowsArrow("Bob", "Charlie");
        
            System.out.println(socialGraph.hasKnowsArrow("Anne", "Bob")); //should be true
            System.out.println(socialGraph.hasKnowsArrow("Anne", "Daisy"));//should be true
            System.out.println(socialGraph.hasKnowsArrow("Bob", "Daisy"));//should be true
            System.out.println(socialGraph.hasKnowsArrow("Bob", "Charlie"));//should be true
            System.out.println(socialGraph.hasKnowsArrow("Anne", "Charlie")); //should be false
        
            System.out.println ();
        
            System.out.println (socialGraph.knowsWithDegree ("Anne", "Daisy", 1));
            System.out.println (socialGraph.knowsWithDegree ("Anne", "Charlie", 2));
            System.out.println (socialGraph.knowsWithDegree ("Anne", "Daisy", 3));
        
        }
    }
}
 

Комментарии:

1. Немного сложно следовать вашему коду со всеми этими map.get(a) звонками и т. Д. Совет для лучшей читабельности: если они возвращают одно и то же, вызовите его один раз и сопоставьте возвращаемое значение переменной с собственным именем. Также улучшите имена ваших параметров, т. Е. a и b трудно следовать — возможно, лучше использовать sourcePerson и targetPerson (источник-это место, где начинается обход графика, цель-там, где она должна заканчиваться).

2. Что касается логики вашего класса: старайтесь совершать по одному «прыжку» за раз, т. е. следуйте стрелкам, пока у вас не закончатся варианты, достигните цикла (сохраняйте набор людей, которых вы уже проверили) или найдите нужного человека. Затем подсчитайте, сколько прыжков вам нужно (возможно, вам придется переносить значение для определенных «маршрутов», если есть несколько способов, т. е. Энн знает Дейзи напрямую (1 прыжок) или через Боба (2 прыжка).

Ответ №1:

Вот пример использования рекурсии:

 

        public boolean knowsWithDegree(String a, String b, int x) {
            return knowsWithDegreeRecursive(a, b, x, new HashSet<>());
        }
        
        private boolean knowsWithDegreeRecursive(String a, String b, int x, Set<String> visited) {
            if (x < 1) {
                // x must be at least 1
                return false;
            }
            

            if (map.get(a).contains(b)) {
                // If a knows b, then the number of degrees should be 1
                return x == 1;
            }
            
            if (x == 1) {
                // Since the degree is 1 and a does not know b, then a does not know b to the specified degree
                return false;
            }
            
            // Go through each person that a knows
            for (String c : map.get(a)) {
                
                if (visited.contains(c)) {
                    // We've already checked this person
                    continue;
                }
                
                // Mark c as visited so we don't check them again
                visited.add(c);
                
                // See if this person knows b, with one fewer degree
                // e.g. if we're seeing if a knows b with a degree of 2, then c should know b with a degree of 1
                boolean knowsWithDegree = knowsWithDegreeRecursive(c, b, x - 1, visited);
                
                // If c knows b with the degree minus 1, then a knows b with the specified degree
                if (knowsWithDegree) {
                    return true;
                }
            }
            
            // a does not know b to the specified degree
            return false;
        }
        

 

Если порядок knowsArrows не имеет значения, я бы рекомендовал использовать HashSet его в вашем map ArrayList приложении .

Комментарии:

1. Невероятно, спасибо вам! Единственная проблема заключается в том, что человек может знать другого человека как 1-й, так и 2-й степени, однако этот код пропустит любые дальнейшие расспросы об этом, поэтому, если человек А знает человека Б, он все равно даст ложные ответы на вопрос, знает ли А Б через С, что должно быть правдой. Но большое вам спасибо, я постараюсь немного поработать с этим сегодня вечером, это было очень полезно!