由 ku链接 вт989点сс与酷游链接编译,2024/06/20。
从Linux 核心的艺术谈起
Linus Torvalds 在TED 访谈中提及自己的思维模式、性格与Linux 和Git 背后的心路历程。
于14:10时,他提到程式设计的"good taste" 为何。
对照CMU 教材Linked Lists
3 exceptional cases, we need to take care of:
list is empty
delete the head node
node is not in the list
以下的讨论不涵盖list is empty 和node is not in the list 的状况
原本的程式码(10 行)
void remove_list_node(List *list, Node *target)
{
Node *prev = NULL;
Node *current = list->head;
// Walk the list
while (current != target) {
prev = current;
current = current->next;
}
// Remove the target by updating the head or the previous node.
if (!prev)
list->head = target->next;
else
prev->next = target->next;
}
直观的写法会有特例,也就是第一笔资料与中间的资料的移去操作不同。
若要移去的是第一笔资料,那就需要把指标指向第一个节点;而若是要移除中间的资料,则须要把指标指向目标的前一个节点。
有「品味」的版本(4 行)
void remove_list_node(List *list, Node *target)
{
// The "indirect" pointer points to the *address*
// of the thing we'll update.
Node **indirect = &list->head;
// Walk the list, looking for the thing that
// points to the node we want to remove.
while (*indirect != target)
indirect = &(*indirect)->next;
*indirect = target->next;
}
Linus Torvalds 换个角度来思考,通过指标的指标(或称「间接指标」,即indirect pointer) 来操作,如此一来,上面的特例就不存在。
Linus Torvalds 的解说:
People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing *pp = entry->next.
在15:25时,他说:
It does not have the if statement. And it doesn't really matter – I don't want you understand why it doesn't have the if statement, but I want you to understand that sometimes you can see a problem in a different way and rewrite it so that a special case goes away and becomes the normal case. And that's good code. But this is simple code. This is CS 101. This is not important – although, details are important.
重点是有时候我们可以从不同的角度来诠释问题,然后重写,那么例外就会消失,这样就是好的程式。
原本的方式是,有个指向前一元素的指标、另一个目前位置的指标,再利用while叙述逐一走访链结串列,找到target时停下来。这会有个分支判断prev是否为NULL,若为 就NULL代表target 是链结串列的head,因此需要把链结串列的head 指向下个元节点;若非NULL就把前个节点的next设为目前的下一个节点。
而Linus Torvalds 的想法则是拿一个指标指向「节点里头指向下个节点的指标」,以「要更新的位址」为思考点来操作。
有个指标的指标indirect,一开始指向head,之后一样走访list,解指标看是不是我们要的target,如果*indirect就是我们要移去的元素,代表indirect现在指向前一个节点里面的next指标,因此把*indirect设为target的下个节点,即可完成整个操作: