今天看到这篇Linus:利用二级指针删除单向链表,作个笔记。
关于在单向链表中删除一个指定的节点,通常有两个易错点。
- 找到指定节点删除时,忘了备份这个节点里指向下一个节点的指针。
- 没有特殊处理删除第一个节点的情况。
//通常的写法 typedef struct node { struct node * next; .... } node; typedef bool (* remove_fn)(node const * v); // Remove all nodes from the supplied list for which the // supplied remove function returns true. // Returns the new head of the list. node * remove_if(node * head, remove_fn rm) { for (node * prev = NULL, * curr = head; curr != NULL; ) { node * const next = curr->next; if (rm(curr)) { if (prev) prev->next = next; else head = next; free(curr); } else prev = curr; curr = next; } return head; }
//Linus所说的利用二级指针的写法。 void remove_if(node ** head, remove_fn rm) { for (node** curr = head; *curr; ) { node * entry = *curr; if (rm(entry)) { *curr = entry->next; //分离要删的节点 free(entry); //回收内存 } else curr = &entry->next; //->符号优先于& } }
第二种写法使用了一个二级指针指向那个指向node节点的指针。关于这个实现,那个文章里已经说的很清楚了。这里只是记录一下对于这个实现的看法。
二级指针的关键在于:二级指针让head指针和next指针在某个特点上处于同一水平。head指针和next最大的不同点是next指针能被别的指针操作。因为next指针属于node结构体中,所以指向node结构体的指针可以携带操作next指针。而head指针没有,没有指针指向它,要修改head的值或者读取head,需要在代码中写明head。而二级指针就解决这个问题,这也就体现了什么是指针。这就是为什么linus说用第一种写法的人不懂指针。因为指针的强大之处在于它能指向任何东西,包括另一个指针。让一个固定了变量名的变量(甚至是一个函数)能作为一个值一样被传递。
是不是必须用二级指针呢?我表示如果单纯为了去掉head指针这个麻烦,我最简单的想法是可以让head指针实体化,即让head先指向一个没用的节点,再让这个节点的next指向链表头节点。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
广告
暂无评论内容