循环列表中的递归调用

时间:2015-09-09 13:48:56

标签: java algorithm graph-algorithm

我试图循环用户列表以找到一个人。每个人都有朋友列表。所以我使用递归调用来检查这个人是否在某人朋友列表中。

我的Junit测试看起来像

@Test
    public void IsInFriendsCicle() throws UserAlreadyInFriendListException, NoFriendFoundException, UsersNotConnectedException {
        User one = new UserImpl("John","Snow");
        User two = new UserImpl("Richard","Gerns");
        User three = new UserImpl("Natalie","Portman");
        User four = new UserImpl("Brad","Pitt");
        User five = new UserImpl("Angelina","Jolie");
        one.addFriend(two);
        two.addFriend(three);
        three.addFriend(four);
        four.addFriend(five);
        assertTrue(one.isInFriendsCycle(five, one.getFriends(), new Stack()));

    } 

因为在这里可以看到,我想知道安吉丽娜是否在约翰的朋友名单中。所以它应该回馈真实。 负责任的方法就是:

public boolean isInFriendsCycle(User userToFind, ArrayList<User> list, Stack stack){
    Stack s = stack;
    ArrayList<User> groupList = list;
    if(groupList.contains(userToFind)){
        return true;
    }else{
        for (User user : groupList) {
            if(!s.contains(user)){
                s.push(user);
                if(user.getFriends().contains(userToFind)){
                    return true;
                }else{
                    return isInFriendsCycle(userToFind, user.getFriends(), s);
                }
                }
        }       
    }
    return false;
}

所以课程是:

public class UserImpl implements User{

    private String name;
    private String surname;
    private static int count = 0;
    private int id;
    private ArrayList<User> friends;
    private ArrayList<Message> messagebox;
    final static Logger logger = Logger.getLogger(UserImpl.class);

    public UserImpl(String name, String surname) {

        this.name = name;
        this.surname = surname;
        this.id = ++count;
        this.friends = new ArrayList<User>();
        this.messagebox = new ArrayList<Message>();
    }
@Override
    public User addFriend(User person) throws UserAlreadyInFriendListException,IllegalArgumentException{
        if(this.getFriends().contains(person)){
            throw new UserAlreadyInFriendListException("user is already in the friendlist");
        }else if(person == null || this.equals(person) ){
            throw new IllegalArgumentException("parameter is null or user trying to add himself as friend");    
        }else{
            this.getFriends().add(person);
            person.getFriends().add(this);
            logger.debug(this.name + " added the user "+person.getName());
            return person;
        }

    }
@Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final UserImpl other = (UserImpl) obj;

        if (this.id != other.id) {
            return false;
        }
        return true;
    }
}

以某种方式存在堆栈问题。我用它来标记人,所以我不进入不定式循环。传递user.getFriends()是有原因的,所以它应该保持这种方式。 任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:1)

我将按如下方式实施:

private Set<User> friends = new HashSet<User>();

public void addFriend(User friend) {
    friends.add(friend);
}

public boolean isImmediateFriend(User user) {
    return friends.contains(user);
}

public boolean isInFriendNetwork(User user) {
    Set<User> visited = new HashSet<>();
    List<User> stack = new LinkedList<>();

    stack.push(this);

    while (!stack.isEmpty()) {
       User current = stack.removeFirst();
       if (current.isImmediateFriend(user)) {
          return true;
       }
       visited.add(current);

       for (User friend : current.getFriends()) {
          // never visit the same user twice
          if (!visited.contains(friend)) {
             stack.addLast(friend);
          }
       }
    }
    return false;
}

答案 1 :(得分:1)

替换

return isInFriendsCycle(userToFind, user.getFriends(), s);

if (isInFriendsCycle(userToFind, user.getFriends(), s)) return true;

如果你没有,如果没有在递归调用的第一个分支中找到它,则会提前退出。你不想要那个 - 你想继续直到你找到它,或者没有什么可以搜索。

顺便说一句 - 你的单位测试并没有帮助你,因为你的筑巢太深了。如果您进行了一些单元测试,首先测试朋友朋友,朋友朋友等等,您就会开始看到它出错的地方。

另外,另外一点:我不会使用Stack(它是legacy class)而是使用Deque代替,这是Java 6+的替代品。但是,在这种情况下,我会使用HashSet<User>形式的Set<User>,因为它适合您的用例和probably performance requirements。我还要在List<User>类和ArrayList<User>方法中将列表变量类型设为UserImpl而不是isInFriendsCycle,只关注合同而不是实现。