Search code examples
c++listrecursionstllistiterator

How do I turn an iterative STL List for loop function into a recursion?


So I have a simple for loop inside a class member function which prints the names of students a university wants to offer admission to. StudentPreferenceList and SchoolName are class member variables and ostr is the file where I want to write the output.

void School::printSchoolPreferences(std::ostream &ostr) const{

    std::list<std::string>::const_iterator name;
    ostr << SchoolName + " preference list:"<< std::endl;
    int rank = 1;

    for (name = SchoolPreferenceList.begin(); name != 
         SchoolPreferenceList.end(); name++){

         ostr << "  " << rank << ". " << *name << std::endl;
         rank++;
    }

}

I am trying to now convert this function into a recursive function and this is what I have so far. My current attempt below gets lots of compilation errors and I will really appreciate if you can help me figure out how to fix it. Thank you.

void School::func(int rank, std::list<std::string>::const_iterator 
                  name_rank, std::ostream &ostr){

     if (rank < SchoolPreferenceList.size()){
         ostr << "  " << rank << ". " << *name_rank << std::endl;
         func(rank++, name_rank++, ostr);
     }
}

void School::printSchoolPreferences(std::ostream &ostr) const{

    std::list<std::string>::const_iterator name;
    ostr << SchoolName + " preference list:"<< std::endl;

    int rank = 1;
    func(rank, name_rank, ostr);
}

This is the expected output:

 university_of_michigan preference list:
   1. erin_jones
   2. john_smith
   3. joe_miller
   4. dave_roberts

Solution

  • Here's a general schema, with short placeholder names.

    Given an iteration as follows:

    void do_something(const Container& c)
    {
        // preamble
        for (auto it = c.begin(); it != c.end(); ++it)
        {
            // per-loop action on *it
        }
    }
    

    You can write the following recursion:

    void do_aux(Container::const_iterator first, Container::const_iterator last)
    {
        if (first == last) return;
    
        // per-loop action on *first
    
        ++first;
        return do_aux(first, last);
    }
    
    void do_something(const Container& c)
    {
        // preamble
        do_aux(c.begin(), c.end());
    }
    

    Note that this is nicely tail-recursive, which shows the essential equivalence of iteration and tail-recursion. The auxiliary function do_aux takes the place of the loop, including checking of the loop condition and breaking. Additional state from the preamble that's needed in the loop body can be passed via additional arguments to do_aux.