简体   繁体   中英

Recursive function in C#

I have a object, let's call it "Friend". This object has method "GetFriendsOfFriend", that returns a List<Friend> .

Given a user input of say 5, all of the Friends friends and the friends friends friends (you get the point) down in a level of 5 (this can be up to 20).

This may be a lot of calculations, so I don't know if recursion is the best solution.

Does anyone have a smart idea of 1. How to do this recursive function best? 2. How to do it without recursion.

Thanks!

Whilst is is certainly possible to do this without recursion, I don't see a particular problem with what you're trying to do. To prevent things going crazy, it might make sense to set a maximum to prevent your program from dying.

public class Friend
{
    public static readonly int MaxDepth = 8; // prevent more than 8 recursions

    private List<Friend> myFriends_ = new List<Friend>();

    // private implementation
    private void InternalFriends(int depth, int currDepth, List<Friend> list)
    {
        // Add "us"
        if(currDepth > 1 && !list.Contains(this))
            list.Add(this);

        if(currDepth <= depth)
        {
            foreach(Friend f in myFriends_)
            {
                if(!list.Contains(f))
                    f.InternalFriends(depth, depth + 1, list); // we can all private functions here.
            }
        }
    } // eo InternalFriends


    public List<Friend> GetFriendsOfFriend(int depth)
    {
        List<Friend> ret = new List<Friend>();
        InternalFriends(depth < MaxDepth ? depth : MaxDepth, 1, ret);
        return ret;
    }  // eo getFriendsOfFriend
} // eo class Friend

EDIT: Fixed an error in the code in that an actual friend would not get added, just "their" friends. This is only necessary when adding friends after a depth of "1" (the first call). I also made use of Contains to check for duplicates.

Here is a non recursive version of this code:

public static void ProcessFriendsOf(string person) {
    var toVisit = new Queue<string>();
    var seen = new HashSet<string>();

    toVisit.Enqueue(person);
    seen.Add(person);           

    while(toVisit.Count > 0) {
        var current = toVisit.Dequeue();    

        //process this friend in some way

        foreach(var friend in GetFriendsOfFriend(current)) {
            if (!seen.Contains(friend)) {
                toVisit.Enqueue(friend);
                seen.Add(friend);
            }
        }
    }
}

It avoids infinite loop by keeping a HashSet of all members already seen and not adding a member to be processed more than once.

It visits friends using a Queue, in a way that is known as Breadth-first search . If we use a Stack instead of a Queue, it becomes a Depth-first search , and would behave pretty much the same as a recursive approach (which uses an implicit stack - the call stack).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM