Рекурсия находит все пути в матрице графа DFS

Я пытаюсь реализовать две функции на основе поиска в глубину с использованием метода рекурсии. В конечном итоге я пытаюсь сравнить время выполнения с алгоритмом warshall (который у меня уже работает). Когда я печатаю свою матрицу, она отклоняется на пару путей.

Рекурсия - это то, что может сбить меня с толку, это моя слабость. Из-за верхнего оператора if if(iIndex1 == iIndex2) return TRUE;, когда я пытаюсь найти путь из (A,A), (B,B), (C,C) и т. д., я всегда получаю 1, даже если пути нет от А до А.

typedef enum { FALSE, TRUE } bool;

/* Recursive function will determine if there is a path from index 1 to 2
 * Based of DFS
 */
bool recPathExists( Graph G, int iIndex1, int iIndex2 )
{
    int j;
    G.nodeArray[iIndex1].visited = TRUE;
    if(iIndex1 == iIndex2){
            return TRUE;
    }
    for(j = 0; j < G.iNumNodes; j++){
        if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j]==1){
            if(recPathExists(G, j, iIndex2))
                return TRUE;
        }
    }
    return FALSE;
}

/* Write a function to find all pairs of nodes which have paths between them.
 * Store this information in the provided pathMatrix.
 */
void allPathsRecFunc( Graph G , int **pathMatrix )
{
    int i, j;
    for(i = 0; i < G.iNumNodes; i++){
        for(j = 0; j < G.iNumNodes; j++){
            if(recPathExists(G, i , j)== TRUE){
                pathMatrix[i][j] = 1;
            }
            resetVisited(G); //resets all nodes to FALSE
        }
    }
}

что должно быть

A   0 1 1 1 1 1 1 1 
B   0 1 0 0 1 1 1 1 
C   0 1 0 0 1 1 1 1 
D   0 0 0 0 0 0 0 0 
E   0 0 0 0 0 0 0 0 
F   0 1 0 0 1 1 1 1 
G   0 1 0 0 1 1 1 1 
H   0 1 0 0 1 1 1 1 

что я получаю

A   1 1 1 1 1 1 1 1 
B   0 1 0 0 1 1 1 1 
C   0 1 1 0 1 1 1 1 
D   0 0 0 1 0 0 0 0 
E   0 0 0 0 1 0 0 0 
F   0 1 0 0 1 1 1 1 
G   0 1 0 0 1 1 1 1 
H   0 1 0 0 1 1 1 1

person below_avg_st    schedule 06.08.2017    source источник
comment
неверные результаты: неправильно каким образом? Кстати, постарайтесь быть последовательным в использовании {} (я рекомендую всегда использовать их, даже для циклов с одним оператором), и: если рекурсия является ответом, обычно в основном императивный язык, такой как C, не является предпочтительным инструментом. .   -  person Marcus Müller    schedule 07.08.2017
comment
@MarcusMüller Я знаю, какой должна быть окончательная матрица, используя алгоритм Warshall. Я использую это, чтобы сравнить его с результатами матрицы, которую я получаю с помощью этого метода. Матрица показывает 1, где должны быть некоторые 0, и наоборот. Только около половины из них точны.   -  person below_avg_st    schedule 07.08.2017
comment
@hnefatl Рекурсивная функция используется для определения наличия пути в графе от узла в iIndex1 к узлу в iIndex2 на основе алгоритма DFS. Цикл for необходим для проверки всех соседних узлов. Мне также нужно будет отмечать посещенные узлы по мере их нахождения.   -  person below_avg_st    schedule 07.08.2017


Ответы (2)


Ваша проблема может быть здесь:

for(j = 0; j < G.iNumNodes; j++)
{
    if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j] == 1)
    {
        return recPathExists(G, j, iIndex2);
    }
}

Выполняя returnобработку результата рекурсии на recPathExists, вы не проверяете другие возможные узлы, которые могут быть доступны в цикле (по сути, вы слишком рано возвращаете ошибку и пропускаете возможные пути).

Я считаю, что вам нужна небольшая модификация:

for(j = 0; j < G.iNumNodes; j++)
{
    if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j] == 1)
    {
        if (recPathExists(G, j, iIndex2))
            return TRUE;
    }
}

То есть «если путь существует, вернитесь в том виде, в котором мы его нашли. Если нет, продолжайте искать».

person hnefatl    schedule 06.08.2017
comment
хорошо, кажется, сработало. Единственная проблема, которая у меня осталась, связана с оператором if вверху if(iIndex1 == iIndex2), когда я говорю (A, A) (B, B) (C, C) и т. д., они всегда будут 1, даже если нет пути для ( А, А). Я изо всех сил пытаюсь понять, что я могу добавить в оператор if, чтобы избежать этого. - person below_avg_st; 07.08.2017
comment
@below_avg_st Самым чистым способом, вероятно, было бы создать функцию-оболочку, которая вызывает вашу существующую функцию. В своей обертке проверьте, что если iIndex1 == iIndex2, то и G.adjMatrix[iIndex1][iIndex2]==1 (что есть петля). Если нет, вызовите существующую функцию. В общем, если у вас есть особый случай в начале, просто добавьте шаг перед началом, чтобы обработать его. - person hnefatl; 07.08.2017

Мой поиск в глубину использует рекурсию, но выводит родительский массив, хотя функциональность должна быть такой же. Он получил отличную оценку, поэтому я знаю, что это работает. Надеюсь, поможет.

https://github.com/grantSwalwell/Data-Structures/blob/master/Depth%20First%20Search.h

Алгоритм~

  1. логический массив, посещаемый для пометки узлов
  2. массив поисковых номеров для измерения глубины доступа
  3. глубину для увеличения и придумать номер поиска
  4. Вызов DFS на 0,0
  5. За каждого не посещенного соседа
  6. Глубина DFS + 1, поиск = глубина, посещено = истина
  7. вернуть родительский массив, показывающий шаблон поиска

    // Depth First Search recursive helper method
    
    
    void DFS(Graph& G, int v0, Array<bool>* visited, Array<int>* search, int 
    depth)
    {
    
        // set visited
        (*visited)[v0] = true;
    
        // set search num
        (*search)[v0] = depth;
    
        // iterate through neighbors
        for (int i = 0; i < G.nodes(); i++)
        {
            // if i is a neighbor
            if (G.edge(i, v0))
            {
                // if it has not been visited
                if (!(*visited)[i])
                {
                     // call DFS
                     DFS(G, i, visited, search, depth + 1);
                 }
             } // end if
         } // end for
    }
    
    // Depth First Search
    Array<int>* DFS(Graph& G, int v0)
    {
    
        // visited array
        Array<bool>* visited = new Array<bool>(G.nodes());
    
        // search number array, order of visitation
        Array<int>* search = new Array<int>(G.nodes());
    
        // initialize both arrays
        for (int i = 0; i < G.nodes(); i++)
        {
            (*visited)[i] = false;
            (*search)[i] = 1;
        }
    
        // create depth field
        int depth = 1;
    
        // call DFS
        DFS(G, v0, visited, search, depth);
    
        return search;
    
    };
    
person Grant Swalwell    schedule 06.08.2017
comment
См. здесь хороший список причин того, почему ответы, содержащие только ссылки, не обязательно являются хорошими ответами. Возможно, обновите свой ответ, включив соответствующий фрагмент кода из вашей ссылки, а также объяснение различий и почему это работает. - person hnefatl; 07.08.2017