转自:https://blog.csdn.net/muclenerd/article/details/42008855
在删除节点,或者进行有序插入时,带有头部哑节点的链表可以简化代码的逻辑。
这种简化体现在我们循环链表时,我们的代码可以不用考虑第一个节点的特殊情况。
我们分别实现两种情况的删除和有序插入接口,就能看出有无头部哑节点对我们代码逻辑的影响。
1.插入
1.1头部有哑节点情况
//按从小到大插入到链表中
void link_insert(link_t *l, link_node_t *node)
{
if( l == NULL )
{
return NULL;
}
link_node_t *p = NULL;
for( p = l; p->next != NULL; p=p->next)
{
if( node->id < p->next->id )
{
node->next = p->next;
p->next = node;
return;
}
}
if( p->next == NULL )
{
p->next = node;
node->next = NULL;
}
}
1.2头部没有哑节点情况
//按从小到大插入到链表中
link_t *link_insert(link_t *l, link_node_t *node)
{
if( l == NULL )
{
return NULL;
}
if( node->id < l->id )
{
node->next = l;
return node;
}
//now make sure that the first element is smaller than node
link_t *p = l->next;
for( ; p->next != NULL; p=p->next)
{
if( node->id < p->next->id )
{
node->next = p->next;
p->next = node;
return l;
}
}
if( p->next == NULL )
{
p->next = node;
node->next = NULL;
}
return l;
}
2.删除
2.1头部有哑节点情况
enum {true, false};
int link_delete(link_t *l, int key)
{
link_t *p = l;
for(; p->next != NULL; p = p->next )
{
if(p->next->id == key)
{
link_t *t = p->next;
p->next = t->next;
t->next = NULL;
free(t);
return true;
}
}
return false;
}
2.2头部没有哑节点情况
int link_delete(link_t **l, int key)
{
if( (*l) == NULL )
{
return NULL;
}
if( (*l)->id == key )
{
*l = (*l)->next;
(*l)->next = NULL;
free(*l);
return;
}
link_t *p = (*l);
for(; p->next != NULL; p = p->next )
{
if(p->next->id == key)
{
link_t *t = p->next;
p->next = t->next;
t->next = NULL;
free(t);
return true;
}
}
return false;
}
可以看到,没有头部哑节点,导致每次我们必须每次在插入或者删除时,必须要对特殊情况,即头节点进行处理。
有了头部的哑节点,我们的处理逻辑就简化了很多。