【问题标题】:Searching a linked list recursively in C在C中递归搜索链表
【发布时间】:2014-02-26 16:09:21
【问题描述】:

我是 C 的新手,我试图编写一个递归搜索链表的方法,但是我没有成功。如果在链表的任何节点中都没有找到该名称,则该函数包含返回 0,并且找到了 1。我似乎陷入了无限循环。任何帮助将不胜感激!

#include<stdlib.h>
#include<string.h>

struct node
{
    char name[1000];
    struct node *next;
};

int contains(const struct node *pNode, const char *name)
{
    int i;
    int length = strlen(name);
    int isEqual = 0;

    while (pNode != NULL)
    {
        isEqual = 1;
        for (i = 0; i < length; i++)
        {
            if (pNode->name[i] != name[i])
            {
                isEqual = 0;
            }
        }
    }

    contains(pNode->next, name);

    return isEqual;
}

main()
{
    struct node node1 = { "Sam", NULL };
    struct node *node1Ptr = &node1;
    struct node node2 = { "Anna", node1Ptr };
    struct node *node2Ptr = &node2;
    struct node node3 = { "Adam", node2Ptr };
    struct node *node3Ptr = &node3;

    int n, k;

    // testing for a name that is the list
    n = contains(node3Ptr, "Sam");
    printf("%d\n", n);
    // testing for a name that is not in the list
    k = contains(node3Ptr, "Max");
    printf("%d\n", k);
}

【问题讨论】:

  • 递归调用contains(pNode-&gt;next, name);忽略返回值,所以没有效果。您比较字符串的方式也是错误的;它将在使用子字符串作为名称参数时创建(例如:“Sa”)

标签: c list search recursion


【解决方案1】:

你的函数可以简洁地写成:

#include <string.h>
...
int contains(const struct node *pNode, const char *name)
{
    if(pNode == NULL)
        return 0;
    if(strcmp(pNode->name, name) == 0)
        return 1;
    return contains(pNode->next, name);
}

请注意,您的代码中对contains() 的递归调用的值从未使用过,因此不会提供任何有用的信息。它的调用在最后无条件地完成,这就解释了无限循环。

编译时启用所有(合理的)警告(-Wall 用于 GCC 和 clang),它应该会告诉您许多嘘声。作为个人政策,如果不是 -Wall clean,最好有充分的理由相信我是对的并且编译器过分热心。

您还可以简化数据结构的大部分设置,但这是另一次了。

很高兴您按照要求使用const 进行了装饰。

【讨论】:

  • 我绝对相信这是一个比我写的更好的版本,我只需要查看 strcmp 函数,但我确实了解它的使用方式,非常感谢。
【解决方案2】:
int contains(const struct node *pNode, const char *name)
{
    if (pNode == NULL)  // Recursive base-case:  If there is no Node,
    {                   // we are at the end of the list, and the name was never found.
        return 0;       // Therefore, return 0
    }

    // If this node matches the name, return 1.  
    // If this node does NOT match the name, check the next node.
    return !strcmp(pNode->name, name)? 1 : contains(pNode->next, name);
}

如果你想要一个非常紧凑的形式:

// Untested, but I think it works... or is at least close.
int contains(const struct node *pNode, const char *name)
{
    return pNode? (!strcmp(pNode->name, name) || contains(pNode->next, name)) : pNode;
}

【讨论】:

  • 感谢您的回答,从我的方法来看,这看起来更简洁,也更有意义,我不熟悉 strcmp 函数,但它确实有意义!谢谢!
【解决方案3】:

如果到达列表末尾,则不应调用函数 contains,但确实会无限调用它。 在通话前添加:

if (pNode ->next != null)
contains(pNode->next,name);

如果它找到项目,你还需要阻止它调用包含,这样你的情况就会像:

if (pNode ->next != null && !isEqual)
contains(pNode->next,name);

【讨论】:

  • 感谢您回答这个问题!
【解决方案4】:

pnodeNULL 之后的 contains 方法中,您再次调用导致无限循环的函数。

修改如下。

if(pnode== NULL) {
return 0;
}

【讨论】:

    【解决方案5】:

    您的无限循环是以下行的直接结果:

    while (pNode != NULL)
    

    因为您永远不会改变pNode 所指的内容。本质上,您是在一遍又一遍地检查Sam...事实上,您甚至从未得到到您的递归调用。

    相反,你会想要一个

    if(pNode != NULL) 
    

    检查,如果没有,检查字符串。如果找到字符串,则返回 1,否则,返回递归调用。

    如果pNode==NULL你想返回0。

    【讨论】:

      【解决方案6】:

      这就是我修改代码的方式,现在它可以工作了。谢谢大家的帮助,我真的很感激,我不熟悉 strcmp 函数,但我会研究一下。再次感谢您。

      int contains(const struct node *pNode, const char *name){
        int i;
        int length = strlen(name);
        int isEqual = 0;
      
        if(pNode == NULL){ 
            return isEqual;
          }
      
        isEqual = 1;
        for (i = 0; i < length; i++)
          {
              if (pNode->name[i] != name[i])
              {
                  isEqual = 0;
                  break;
              }
          }
      
      
       return isEqual? isEqual : contains(pNode->next, name);
      }
      

      【讨论】:

        猜你喜欢
        • 2015-06-14
        • 2017-11-23
        • 1970-01-01
        • 2019-09-17
        • 1970-01-01
        • 2010-12-01
        • 1970-01-01
        • 2013-07-20
        • 1970-01-01
        相关资源
        最近更新 更多