使用二级指针操作链表

当然,我学的第一门编程语言是C语言(虽然现在很少使用C语言了,都是用一些抽象做的很高的语言),对于C语言,我是很、非常、及其的认真的学习,因为C是能够让你非常贴切的认识各种东西的语言,通过C语言你可以了解到编译原理的一些知识,可以辅助你读操作系统的源码,可以写一些高效的代码,当你学习汇编语言的时候,你会发现C语言与汇编语言的千丝万缕的联系,当你学习C++的时候的有C的基础是非常必要的。所以如果想学好编程,了解C语言是非常的必要的。

当然每个学习过C的人都曾被C的指针折磨过(不过俺可没有,因为俺到后面关于指针的本质问题了解了,所以就可以以不变应万变了),虽说指针的原理我是非常的懂了,但是关于指针的一些用法,尤其是一些比较高端的用法,就拿二级指针来说吧,我总是觉得非要间接两次才能取到变量有啥意义,不过今天突然看到了一个使用二级指针的操作,非常好,在此分享一下。

指针的一个重要的使用点是对于链表的操作。语言链表如果删除一个指定的节点的操作,通常的解决方案如下:

typedef struct node
{
    struct node *next;
    //satellite data...
    int data;
}Node;


typdef bool (* rmNode)(const Node *v);

Node * removeIf(Node *head, rmNode rmFunc)
{
    for(Node *pre=NULL, *current=head; current!=NULL;)
    {
        Node *next=current->next;
        if(rmNode(current))
        {
            if(pre==NULL)
            {
                head=next;
            }
            else
            {
                pre->next=next;
            }
            free(current);
        }
        else
        {
            pre=current;
            current=current->next;
        }
    }

    return head;
}

 

对于这个解决方案,你需要维护三个指针pre,current,next, 而且需要对head被删除做特殊的考虑,那么每次循环都会有判断的开销。

 

而使用二级指针的解决方案可以做成如下的效果:

void removeIf(Node **head, rmNode rmFunc)
{
    for(Node** current=head; *current!=NULL)
    {
        Node *entry=(*current)->next;
        if(rmNode(entry))
        {
            (*current)=entry->next;
            free(current);
        }
        else
        {
            current=&(entry->next);
        }

    }
}

首先使用指针减少为两个了:current,entry ,而且不需要考虑首节点的情况,效率提高了。但是这个代码如果你对二级指针的理解不是很清楚的情况下,那么就不是特别的易读,当然你懂了那就另说了(虽然我懂了,但是感觉不写上一两百遍感觉还是不是特别容易的编程肌肉记忆)。

附注:这个可以linux内核当中实用的单项,双向链表中经常用到的技巧,而且linus在新闻组还说过的。这个技巧是我从coolshell上面看到的,coolshell(www.coolshell.cn)是一个特别好的技术blog,里面有很多不错的东西,很是值得学习,而且可以放到rss上。

 

 

 

posted on 2014-04-17 18:34  itat  阅读(484)  评论(0编辑  收藏  举报

导航