Search code examples
c++iteratordiscrete-mathematics

Check if the given relations are transitive and if not, add new pairs to make it transitive


I'm trying to check if the given relations are transitive and if not, add new pairs of relations to make it transitive. Example input:

aa ab ad be

Function should make this: aa ab ad be ae because in order to be transitive, if ab and bc exists, ac must exist too. But I get a segmentation fault whatever I try.

I'm new to C++ programming and trying to learn about iterators. Here is my function:

vector<string> isTransitive(vector<string> relations){
    bool flag;
    for(auto it=relations.begin();it != relations.end(); ++it){ 
        for(auto it2=relations.begin();it2 != relations.end(); ++it2){
            if((*it)[1] == (*it2)[0] && (*it)[0] != (*it)[1] && (*it2)[0]!=(*it2)[1]){ //if there exists ab and bc
                string newRelation;  //if there is a (a,b) (b,c) holds (a,c)
                newRelation.push_back((*it)[0]);
                newRelation.push_back((*it2)[1]);
                flag=false;
                for(auto it3=relations.begin();it3 != relations.end(); ++it3){
                    if(*it3==newRelation){
                        flag=true;
                        it3=relations.end(); //break the loop
                        it2=relations.end(); //break the loop
                    }
                }
                if(flag==false){
                    relations.push_back(newRelation);
                }
            }
        }
    }
    return relations;
}

if(*it3==newRelation) when this statement is true, I get the segfault.


Solution

  • A for loop is equivalent to a while loop (from cppreference):

    {
    
        init_statement
        while ( condition ) {
    
            statement
            iteration_expression ;
    
        } 
    
    } 
    

    With this two lines:

    it3=relations.end(); //break the loop
    it2=relations.end(); //break the loop
    

    You are not breaking the loop, but you cause undefined behavior. Both iterators will be incremented first, then the loop condition is checked. At that point it3 is no longer relations.end(). It is more or less like this:

    {
        auto it = relations.begin();
        while (it != relations.end()) {
            it = relations.end();
            ++it;
        }
    }
    

    The condition will never be true and you run beyond the end of relations.

    To break out of loops use break. To break out of nested loops, you can put them in a function and use return.