递归查找列表中的最小偶数

Find the minimum even number in a list recursively

我写过这个函数:

struct nodo * MinimoPariListaRic(struct nodo * top) {
  struct nodo * minimo_p = NULL; //this should be the minimum even number

  //list have one or no one element
  if(top) {
    if(!top->next) 
        if(top->valore % 2 == 0) return top; // valore(italian) = value
        else return NULL;
  }
  else return NULL;


  if(top->next)
    minimo_p = MinimoPariListaRic(top->next);

  if (top->valore % 2 == 0)
  {
     if(minimo_p->valore < top->valore) return minimo_p;
     else return top;
  }
  else return minimo_p;
}

如果列表的元素都是偶数,函数会return取最小值,就可以了。 但如果出现奇数,则该功能无法正常工作。 如果所有数字都是奇数,函数应该 return NULL.

你的算法是错误的,如果递归调用 return NULL 因为将 minimo_p 设置为 NULL,你可能会有未定义的行为,如果 (top->valore % 2 == 0),你将取消引用它,它太复杂了,你不需要递归调用,只是去抛出列表,例如:

struct nodo * MinimoPariListaRic(struct nodo * l) {
  struct nodo * minimo_p = NULL; //this should be the minium even number

  while (l != NULL) {
    if (l->valore % 2 == 0) {
      if ((minimo_p == NULL) || (l->valore < minimo_p->valore))
        minimo_p = l;
    }
    l = l->next;
  }

  return minimo_p;
}

因为您编辑的主题需要递归调用,例如您可以这样做:

struct nodo * MinimoPariListaRic(struct nodo * l) {
  if (l == NULL)
    return NULL;
  else {
    struct nodo * minimo_p = MinimoPariListaRic(l->next);

    return ((l->valore % 2 == 0) &&
            ((minimo_p == NULL) || (l->valore < minimo_p->valore)))
       ? l :  minimo_p;
  }
}

如您所见,这很简单,如果 valore 是否为奇数,我在程序中只检查一次等


使用完整程序检查:

#include <stdio.h>
#include <stdlib.h>

struct nodo {
  struct nodo * next;
  int valore;
};

struct nodo * MinimoPariListaRic(struct nodo * l) {
  if (l == NULL)
    return NULL;
  else {
    struct nodo * minimo_p = MinimoPariListaRic(l->next);

    return ((l->valore % 2 == 0) &&
            ((minimo_p == NULL) || (l->valore < minimo_p->valore)))
       ? l :  minimo_p;
  }
}

int main(int argc, char ** argv)
{
  /* make a list from the args */
  struct nodo * l = NULL;
  
  while (argc > 1) {
    struct nodo * r = malloc(sizeof(*r));
    
    r->next = l;
    if (sscanf(argv[--argc], "%d", &r->valore) != 1) {
      puts("invalid number");
      return 0;
    }
    l = r;
  }
  
  /* show list well made */

  struct nodo * ll;
  
  for (ll = l; ll != NULL; ll = ll->next)
    printf("%d ", ll->valore);
  putchar('\n');
  
  /* */
  
  ll = MinimoPariListaRic(l);
  
  if (ll == NULL)
    puts("no even value");
  else
    printf("min even value is %d\n", ll->valore);
  
  /* free resources */

  while (l) {
    ll = l->next;
    free(l);
    l = ll;
  }
  
  return 0;
}

编译与执行:

pi@raspberrypi:/tmp $ gcc -Wall l.c
pi@raspberrypi:/tmp $ ./a.out 1 4 2 7 8
1 4 2 7 8 
min even value is 2
pi@raspberrypi:/tmp $ ./a.out

no even value
pi@raspberrypi:/tmp $ ./a.out 3
3 
no even value
pi@raspberrypi:/tmp $ ./a.out 3 3 1 5
3 3 1 5 
no even value
pi@raspberrypi:/tmp $ valgrind ./a.out 3 4 5 2 0
==16881== Memcheck, a memory error detector
==16881== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16881== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==16881== Command: ./a.out 3 4 5 2 0
==16881== 
3 4 5 2 0 
min even value is 0
==16881== 
==16881== HEAP SUMMARY:
==16881==     in use at exit: 0 bytes in 0 blocks
==16881==   total heap usage: 6 allocs, 6 frees, 1,064 bytes allocated
==16881== 
==16881== All heap blocks were freed -- no leaks are possible
==16881== 
==16881== For lists of detected and suppressed errors, rerun with: -s
==16881== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi@raspberrypi:/tmp $ 

因为如果列表在最后位置和[=18=包含奇数整数,则minimo_p在递归的函数returns之后可以为NULL ]任何地方至少有一个偶数.

这行是错误的:

if(minimo_p->valore < top->valore) return minimo_p;

您可以在此处添加空条件:

if(minimo_p && minimo_p->valore < top->valore) return minimo_p;

如果你必须使用递归,你应该先尝试用伪语言写下来:

  • 如果当前列表只有一个元素
    • -> return if even, else return null
  • 如果列表有更多元素
    • 获取列表剩余部分的最小值
    • 如果当前元素是奇数
      • return 其余最小值
    • 否则如果其余为空
      • return这个元素
    • else 如果 rest 不为空
      • return小的那个

我不会对此提出异议。如果列表很长,您的堆栈就会崩溃。

一个简单的循环会更简单,更省心:

  • 初始化最小值为NULL
  • 用列表初始化迭代器
  • while 迭代器 != Null
    • 如果迭代器偶数和最小值 == Null
      • 最小=迭代器
    • else if even and iterator < minimum
      • 最小=迭代器
    • 高级迭代器

我的五分钱。我还包含了一个递归函数,用于查找具有最大偶数的节点。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

struct nodo
{
    int valore;
    struct nodo *next;
};

int push_front( struct nodo **top, int valore )
{
    struct nodo *nodo_nuovo  = malloc( sizeof( struct nodo ) );
    int success = nodo_nuovo != NULL;
    
    if ( success )
    {
        nodo_nuovo->valore = valore;
        nodo_nuovo->next = *top;
        *top = nodo_nuovo;
    }
    
    return success;
}

FILE * display( struct nodo *top, FILE *fp )
{
    for ( ; top != NULL; top = top->next )
    {
        fprintf( fp, "%d -> ", top->valore );
    }
    
    fputs( "null", fp );
    
    return fp;
}

struct nodo * MinimoPariListaRic( struct nodo * top )
{
    if ( !top )
    {
        return top;
    }
    else
    {
        struct nodo *minimo = MinimoPariListaRic( top->next );
        
        
        if ( minimo == NULL )
        {
            minimo = top->valore % 2 == 0 ? top : minimo;
        }
        else if ( top->valore % 2 == 0 )
        {
            minimo = minimo->valore < top->valore ? minimo : top;
        }

        return minimo;
    }
}

struct nodo * MassimoPariListaRic( struct nodo * top )
{
    if ( !top )
    {
        return top;
    }
    else
    {
        struct nodo *massimo = MassimoPariListaRic( top->next );
        
        
        if ( massimo == NULL )
        {
            massimo = top->valore % 2 == 0 ? top : massimo;
        }
        else if ( top->valore % 2 == 0 )
        {
            massimo = top->valore < massimo->valore ? massimo : top;
        }

        return massimo;
    }
}

int main(void) 
{
    struct nodo *top = NULL;
    enum { N = 10 };
    
    srand( ( unsigned int )time( NULL ) );
    
    for ( int i = 0; i < N; i++ )
    {
        push_front( &top, rand() % N );     
    }

    fputc( '\n', display( top, stdout ) );
    
    struct nodo *minimo = MinimoPariListaRic( top );
    
    if ( minimo != NULL )
    {
        printf( "Minimo pari valore is %d\n", minimo->valore );
    }
    else
    {
        puts( "there is no minimo pari valore" );
    }
    
    struct nodo *massimo = MassimoPariListaRic( top );
    
    if ( massimo != NULL )
    {
        printf( "Massimo pari valore is %d\n", massimo->valore );
    }
    else
    {
        puts( "there is no massimo pari valore" );
    }

    return 0;
}

程序输出可能看起来像

8 -> 9 -> 9 -> 9 -> 7 -> 9 -> 7 -> 3 -> 1 -> 2 -> null
Minimo pari valore is 2
Massimo pari valore is 8

至于你的函数定义那么你需要检查指针是否 minimo_p 调用返回

  if(top->next)
    minimo_p = MinimoPariListaRic(top->next);

在下一个 if 语句中等于 NULL

  if (top->valore % 2 == 0)
  {
     if(minimo_p->valore < top->valore) return minimo_p;
     else return top;
  }