【问题标题】:How to dynamically populate Linked List with Fibonacci series如何使用斐波那契数列动态填充链表
【发布时间】:2022-12-09 11:35:11
【问题描述】:

我有一个链表,我想将其填充到某个循环编号。我下面的代码显示了使用 C 链表的斐波那契数列。

这是我没有任何循环的代码:

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

typedef struct Node 
{
    int count;
    int fibo;    
    struct Node* next;

}node;

int
fibo(int val){
        if(val == 1 || val == 2) {
                return 1;
        }
        return fibo(val - 1) + fibo(val - 2);
}

int
main (void)
{
    node f1, f2, f3;

    f1.count = 1;
    f1.fibo = fibo(1);

    f2.count = 2;
    f2.fibo = fibo(2);

    f3.count = 3;
    f3.fibo = fibo(3);

    f1.next = &f2;
    f2.next = &f3;
    f3.next = NULL;


    printf("f1 fibo : %i\n", f1.fibo);
    printf("f2 fibo : %i\n", f2.fibo);
    printf("f3 fibo : %i\n", f3.fibo);

    return (0);
}

现在我想通过循环来做到这一点。我该怎么做?

【问题讨论】:

  • 为什么需要斐波那契数列的链表?为什么递归 fibo 函数会为每个项重新计算整个序列?
  • 缩进代码时,切勿使用制表符,因为每个文字处理器//编辑器的制表位/制表符宽度设置不同。建议始终为每个缩进级别使用 4 个空格,因为它足够宽,可以看到,即使使用可变宽度字体,也允许在页面上使用多个缩进级别
  • 为了便于理解和阅读,1) 遵循公理:每行只有一个语句,每个语句(最多)一个变量声明。2) 使用有意义的变量名。变量名称应指示用途或内容(或更好的是,两者)。
  • 你知道如何实现链表吗?你知道如何将另一个元素附加到链表吗?你知道如何通过malloc()函数分配内存吗?你知道怎么写循环吗?
  • fibo() 函数不需要使用递归。只有几个静态变量可以保存前两个计算出的数字。

标签: c


【解决方案1】:

对于这个答案,我将忽略每次调用 fibo(n) 时重新计算所有斐波那契数直到您检索的给定数所引起的计算效率问题。

链表通常不是允许您访问具有索引的任意元素的“随机访问”数据结构。使用带指针的链表时,只需要将指针指向链表的(第一个元素)。然后,您使用遍历每个 next 链接的循环从头开始遍历列表。如果列表为空,则您的通常为 NULL。

你可以在这里申请。一种方法(有几种)是定义一个函数来分配和设置单个条目:

node *set_fibo(int n)
{
    node *fibo_entry = malloc(sizeof(node));

    if ( fibo_entry == NULL ) {
        // error
    }

    fibo_entry->count = n;
    fibo_entry->fibo = fibo(n);
    fibo_entry->next = NULL;
    return fibo_entry;
}

然后在你的主要:

node *fibo_list = NULL;
node *last_fibo = NULL;

// Assume n_fibo is the number of Fibonacci numbers you want to store in order
for ( int n = 1; n <= n_fibo; n++ ) {
    if ( n == 1 )
        fibo_list = last_fibo = set_fibo(1);
    else {
        last_fibo->next = set_fibo(n);
        last_fibo = last_fibo->next;
    }
}

【讨论】:

    【解决方案2】:

    虽然问题已经得到解答,但我想补充一些关于代码效率方面的内容。如前所述,您不必从头开始计算 fibo 值,因为您将最新结果保存在单链表中。 因此,假设您有以下列表 1-1-2-3-5-,您可以通过简单地添加两个后期元素(即 35)的菲波值来轻松计算新节点的菲波值。因此新节点的 fibo 值应该是8

    给定指向倒数第二个元素的指针,此函数将向列表添加一个新节点并设置正确的 fibo 值:

    void addNode(struct Node* node){
        struct Node* n = malloc(sizeof(struct Node));
        n->next = NULL;
        n->count = node->next->count + 1;
        n->fibo = node->fibo + node->next->fibo;    
        node->next->next = n;
    }
    

    为了使用此功能,您必须在列表中创建前两个节点:

    struct Node* n2 = malloc(sizeof(struct Node));
    n2->count = 2;
    n2->fibo = 1;
    n2->next = NULL;
    struct Node* n1 = malloc(sizeof(struct Node));
    n1->count = 1;
    n1->fibo = 1;
    n1->next = n2;
    

    如果你现在想添加——比方说 10 个——新节点,你只需执行以下操作:

    struct Node* ptr = n1;
    int i;
    for(i=0; i<10;i++) {
        addNode(ptr);
        ptr = ptr->next;
    }
    

    如果现在要打印列表中所有节点的条目,只需遍历列表直到到达NULL

    ptr = n1;
    while(ptr != NULL) {
        printf("fib(%d) = %d
     ", ptr->count, ptr->fibo);
        ptr = ptr->next;
    }
    

    请记住,您必须手动释放动态分配的项目!

    【讨论】:

      【解决方案3】:

      在您的示例中,节点是main 中的自动变量。它们不是动态分配的,只要您不从main 返回,它们就会一直存在。您可以使用自动节点数组扩展此概念:

      #include <stdio.h>
      #include <stdlib.h
      
      typedef struct Node Node;
      
      struct Node {
          int count;
          int fibo;    
          Node* next;
      };
      
      #define N 30
      
      int main (void)
      {
          Node fibo[N];
          Node *head = NULL;
          Node **p = &head;
      
          int f1 = 0;
          int f2 = 0;
      
          for (size_t i = 0; i < N; i++) {
              Node *nd = &fibo[i];
      
              nd->count = i + 1;
              nd->fibo = f2 + f1 ? f2 + f1 : 1;
      
              f1 = f2;
              f2 = nd->fibo;
      
              *p = nd;
              p = &(*p)->next;
          }
          *p = NULL;
      
          Node *nd = head;
      
          while (nd) {
              printf("fib(%d) == %d
      ", nd->count, nd->fibo);
              nd = nd->next;
          }
      
          return (0);
      }
      

      但是,尚不清楚为什么需要斐波那契数列作为链表。另外,请注意:不要在列表中混合堆栈上的节点(如此处)和堆上的节点(如潜伏者的回答)。这个答案只是将你的答案扩展到许多节点,而 lurker 的答案显示了链表的更一般概念。

      【讨论】:

        【解决方案4】:

        这是我认为你可以做到的。您可以为节点使用数组。

        node f[3];
        int i;
        
        for ( i = 0 ; i < 3 ; i++ )
        {
            f[i].count = i+1;
            f[i].fibo = fibo (i+1);
            if ( i == 2 )
            {   
                f[i].next = NULL;
            }
            else
            {
                f[i].next = &f[i+1];
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2019-05-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-26
          • 2014-03-06
          • 1970-01-01
          • 2015-06-05
          相关资源
          最近更新 更多