【问题标题】:C - Depth first search in adjacency matrix using recursionC - 使用递归在邻接矩阵中进行深度优先搜索
【发布时间】:2019-04-04 19:36:06
【问题描述】:

我有一个递归问题想用递归来解决。

例如,给定这个邻接矩阵 AdjMat:

  0 1 2 3 
0 0 1 0 0
1 1 0 1 0
2 0 1 0 1
3 0 0 1 0

假设我想查看第 0 列及其所有邻居,以及其邻居的邻居(距离为 2),并将所有行索引 > 0 存储到一个整数链表中。

这是我更新的代码:

intNode *Neighbors(intNode *head, int colOfInterest, int distance) {
    int x = colOfInterest; 

    if (distance == 0) {
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
               if (AdjMat[x][j] > 0) { 
                   head = insertInt(head, j);
               }
            }
            break;
        }
    }
    intNode *subpath = NULL;
    for (int i = 0; i < distance; i++) {
        subpath = Neighbors(head, colOfInterest, distance);
    }
    // Once the final neighbor column has been reached, add elements to the linked list.
    return head;
} 

它目前没有返回预期的输出(即链表中的 0、1 和 2),但我不知道为什么。任何帮助或指导表示赞赏。

【问题讨论】:

  • 嗯。当您递归调用nearestNeighbors 时,您可能希望保存返回值,即新的列表头。你应该下定决心是否要使用递归或循环迭代。您的代码似乎是两者的混合体。
  • 你能用伪代码解释一下这个循环应该做什么吗?目前您多次访问单元格,我认为您需要明确的规则来停止递归。但我根本不明白它应该做什么。
  • 使用与当前化身相同的值调用递归。
  • 如果必须使用递归解决问题,那么我怀疑您已经倒退了。您似乎没有设计解决方案的递归公式然后实施它,而是设计了一个解决方案,然后尝试将一些递归插入其中。
  • 正如我所说,在尝试实现它之前,递归地制定问题。例如,假设您要计算从起始节点通过长度为 d 的路径可到达的节点集合 N(d)。好吧,我们可以递归地定义它,因为所有节点都与 N(d - 1) 中的任何节点相邻。如果我们然后让 N(0) 是包含(仅)起始节点的集合,那么我们就有了一个完整的解决方案基础。

标签: c recursion adjacency-matrix


【解决方案1】:

您的代码中有两个主要的误解。第一个是关于递归的,第二个是关于邻接矩阵的工作原理。

递归基本上是这样工作的:

  • 取一个节点和一个最大值。距离:func(node, d);
  • 如果距离为负,则返回
  • 将节点添加到列表中;
  • 对于所有相邻节点,调用该节点上的函数并使用新的、现在更短的距离:func(next, d - dist(node, next)。

要查找节点 #0 附近的所有节点,您可以从一个空列表开始,然后调用 func(0, 2),这将导致以下调用:

func(0, 2)                  // list {0}
    func(1, 1)              // list {0, 1}
        func(0, 0)          // list {0, 1, 0}          error, see below
            func(1, -1)     // negative d, do nothing
        func(2, 0)          // list {0, 1, 0, 2}
             func(1, -1)    // negative d, do nothing
             func(3, -1)    // negative d, do nothing

--> recursion depth

此递归最终将停止,因为您在每一步中都会减少距离。这很重要:每个递归都必须有一个终止条件,否则它将无休止地递归。 (无论是在前面测试距离还是在递归时测试距离都是风格问题。向上字体会尽早捕获无效输入,但可能会导致无用的“死”递归。)

给定的递归有一个微妙的问题:当您调用 func(0, 2) 时,该函数将添加节点 #0 两次,因为从节点 0 到 1 然后返回到 0 会产生距离 2,这是可以达到的。有几种方法可以解决这个问题。例如,您可以查看给定节点是否已经在您的列表中。或者您可以随时将节点标记为已访问。

邻接矩阵确定两个节点是否连接。如果adj[a][b] != 0,则连接两个节点a 和b。这意味着如果你想找到给定节点node 的所有邻居next,你应该这样做:

for (int next = 0; next < N; next++) {
    if (adj[node][next]) {
        // do something with next
    }
}

您不需要两个嵌套循环。矩阵有两个维度,但第一个始终是固定的:它是源节点。 (如果您查看您的代码,您会发现您没有对 i 执行任何操作。)

在您的情况下,邻接矩阵似乎只有 0 和 1 的值,但它可能有其他非零值来指示加权图的距离。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多