我有一个链表,我想填充一个特定的循环号。我在下面的代码中显示了使用C链接列表的Fibonacci系列。
这是我没有任何循环的代码:
#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);
}
现在我想通过循环来做到这一点。我该怎么做?
答案 0 :(得分:1)
对于这个答案,我将忽略因重新计算所有Fibonacci数字而产生的计算效率问题,直至每次调用fibo(n)
时检索到的给定数字。
链接列表通常不是&#34;随机访问&#34;允许您使用索引访问任意元素的数据结构。使用带指针的链接列表时,只需要指向链接列表的 head (第一个元素)。然后,您使用循环遍历每个next
链接从头部开始遍历列表。如果列表为空,则 head 通常为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;
}
}
答案 1 :(得分:1)
虽然问题已经得到解答,但我想补充一些关于代码效率方面的内容。如前所述,您不必从头开始计算fibo值,因为您将最新结果保存在单链表中。
因此,如果您有以下列表1-1-2-3-5-
,则可以通过简单地添加两个元素(即3
和5
)的fibo值来轻松计算新节点的fibo值。因此,新节点的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\n ", ptr->count, ptr->fibo);
ptr = ptr->next;
}
请记住,您必须手动释放动态分配的项目!
答案 2 :(得分:0)
在您的示例中,节点是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\n", nd->count, nd->fibo);
nd = nd->next;
}
return (0);
}
但是,为什么你需要斐波纳契系列作为链表,目前尚不清楚。还有一句警告:不要在列表中混合堆栈上的节点(如此处)和堆上的节点(如潜伏者的答案)。这个答案只是将你的答案扩展到许多节点,而潜伏者的答案显示了链接列表的更一般概念。
答案 3 :(得分:0)
以下是我认为你可以做到的。您可以为节点使用数组。
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];
}
}