我正在重构一些C代码,因为有一段时间我挂起了与链表数据结构相关的问题。请查看以下简化代码段:
Link apply(Link first, pred_ptr cond)
{
Link t=first->next,p=first;
do{
if(cond(t))
{
p->next=t->next;
free(t);
t=p;
}
p=t;
t=t->next;
}while(t!=first);
//Check the first
if(cond(first))
{
t=first->next;
free(first);
first=t;
p->next=t;
}
return first;
}
函数 apply 删除链接列表中 cond 函数返回非零值的所有元素。 链接是这样的:
struct node
{
struct node* next;
//Stuff
};
typedef struct node* Link
嗯,我唯一的问题是如何应用删除链接列表的第一个元素 - first - ,看起来像循环中的额外代码为了评估第一个元素是必需的,我没有能够在没有额外的 if 语句的情况下将这个检查放在循环中,也许你可能知道如何从循环中删除额外的代码 - 如果可能 - 你呢?
谢谢,
度过愉快的一天。
答案 0 :(得分:0)
第一个元素是一个特例,所以你会得到一个与其他案例略有不同的代码就不足为奇了。所以你的选择是(1)在你的例子中完成它的方式,(2)将特殊情况代码放在主循环中,每次迭代执行if比较,或者(3)使用指针指针的不易理解的版本。 / p>
你应该问自己的第一个问题是:你为什么要重构?为清楚起见,还是因为需要更快的实施?或者......?
答案 1 :(得分:0)
您的代码逻辑几乎正确,但在某些地方存在各种问题:
link list
实际上是circular link list
,因为如果没有,某些节点中的某些->next
将是== NULL
。并且代码不会在任何地方检查NULL
,在while循环结束之前的t=t->next;
之类的行将在达到NULL时执行未定义的行为。假设cond
函数与NULL
一起正常工作而不输入if
语句(如果输入, UB 将在此处执行p->next=t->next;
)。如果link list
只是link list
而不是循环,则代码需要大量重构。 linked list
或circular linked list
中的第一个元素可以单独分析,在简单linked list
的情况下,这样做会更好,因为循环分析其余的节点的可读性更强,无需处理特定情况(将在循环中处理,并且在{{1}的情况下,您不会通过检查第一个节点来重载另一个节点的分析。第一个元素可以优雅地在循环中进行分析,但也可以在循环中进行分析。
顺便提一下,如果这是实际代码中使用的变量名,那么你已经在重构中了(p - > previous,t - > test?我认为等等......)