contributed by < willy-liu >
1
根據定義
#include <stddef.h>
typedef struct list_item {
int value;
struct list_item *next;
} list_item_t;
typedef struct {
struct list_item *head;
} list_t;
要實作list_insert_before
,就要先遍歷鏈結串列,找到before。最簡單的做法其實只需要*p
就好,實作如下
{
list_item_t *p;
if (l->head == before) {
item->next = l->head;
l->head = item;
return;
}
for (p = l->head; p && p->next != before; p = p->next);
if (p) {
item->next = p->next;
p->next = item;
}
}
首先找到要插入的位置,然後將item->next
設定為p->next
,最後讓p->next
等於item就好。
然而,這樣的實作方式在邊界條件就會有例外,before
如果在head
就需要將l->head
取代成item
。這樣的例外就是一個不好的code smell,特別是在雙向鏈結串列,或是其他結構,如果邊界情況有好幾個時,不但會影響程式碼的閱讀,還會影響效能。
使用了**p
就可以完美解決這樣的邊界情況,將遍歷的對象從節點本身,改為在next
指標的位址上做移動,head
的型態也與next
相同,所以對p取址一次*p
就可以變更l->head
或是list_item->next
,邊界情況要做的事與一般情況的邏輯就會一致。
{
list_item_t **p;
for (p = &l->head; *p != before; p = &(*p)->next);
item->next = *p;
*p = item;
}
要實作合併排序,需要
2
3
1
2
3