我开始在C中编写链表实现:
typedef struct node node;
struct node {
node *next;
int value;
};
我可以轻松编写将新节点附加到列表末尾的函数append:
void append(node *head, int value) {
if (! head->next) {
head->next = malloc(sizeof(node));
head->next->value = value;
return;
}
append(head->next, value);
}
如果我使用像Scheme这样的函数式语言编写前置,那么显而易见的事情就是简单地返回一个新节点,其中“next”指向前一个头:
(define (prepend head value)
(cons value head))
我可以在C中轻松写出这个:
node *prepend(node *old_head, int value) {
node* head = malloc(sizeof(node));
head->value = value;
head->next = old_head;
return head;
}
但是现在我的append函数没有返回任何东西,只是改变了列表,而我的prepend函数确实返回了一些东西并且没有改变原始列表.这是链接列表实现方式的副作用,但感觉不对.
一种解决方案可能是重写prepend以添加新节点,但使用前一个头来获取新值,将新节点用于旧头的值…
void prepend(node *head, int value) {
node* new = malloc(sizeof(node));
memcpy(new, head, sizeof(node));
head->next = new;
head->value = value;
}
但是这件事也有些不对劲.
另一种解决方案可能是将列表表示为不作为头节点,而是作为指向头节点的不同结构:
typedef struct list list;
struct list {
node *head;
};
现在我的prepend函数可以改变list-> head points的位置,而且它不必返回任何东西.这感觉最干净,但它引入了额外的行李;现在我必须使用辅助函数来追加和许多其他函数(或者以不同的方式实现它们).
在C中实现此功能的惯用方法是什么?
注意:我是C的新手,我很感激有关我的代码风格或正确性的任何评论,即使与问题无关.
最佳答案 在我看来,没有“正确”的答案,但我喜欢结构列表方法.您甚至可以使其对最终用户不透明.然后,您可以将底层实现更改为双向链接列表或由数组支持,并且用户无需更改任何代码即可利用它.