进一步思考-关于Linus: 大多黑客甚至连指针都未理解

来源:互联网 发布:淘宝淘货源插件 编辑:程序博客网 时间:2024/06/05 15:33
看到CSDN上一篇关于Linus回答问题的文章,感觉很是有趣。
链接: Linus问答
    文章
    
在问答中,Linus指出,"大多数黑客甚至连指针都未理解", 对此不敢有任何的评论。我所关注的主要是Linus讲的利用二级指针删除链表元素的方法。
方法的思想是:链表中每一个元素都有一个指针指向,那么可以使用一个二级指针来遍历每一个元素,可以"非常自然流畅"的完成删除工作,避免了条件判断和prev指针。
这里说明,这里并不是要讨论什么"奇技淫巧",我关注的是方法本身,以及方法的推广。如果有任何想法,都可以和谐讨论。
该方法有一个关键是,利用链表每个元素都有指针指向这样一个特性(为什么我从来没有想过在遍历的时候,利用这个特性那?)。
根据这一点,可以想到,在链表其他操作中同样可以使用这一方法。以下是我编写的操作list的代码,包括Linus讲的remove方法,还有数个create方法。个人拙见。


#include <stdio.h>#include <malloc.h>typedef struct{    int number;    struct node *next;}node;typedef int (*remove_fn)(const node *pn);node* remove_list(node *head,remove_fn rm){    node **cur=&head;    for(;*cur;)    {        node *entity=*cur;        if(rm(entity))        {            *cur=entity->next;            free(entity);        }else            cur=&entity->next;    }    return head;}/** * 删除小于0的节点 */int rm(const node *pn){    if(pn->number<0)        return 1;    return 0;}//打印链表void print(const node *head){    while(head)    {        printf("node-number=%d\n",head->number);        head=head->next;    }}//第一种非linus方法,创建n个元素的链表node *create_normal_1(int n){    node *head=NULL,*tail=head;    int i;    for(i=1;i<=n;++i)    {        node *new=(node*)malloc(sizeof(node));        printf("input number:"); scanf("%d",&new->number);        new->next=NULL;        if(!head)        {            head=new;        }else        {            tail->next=new;        }        tail=new;    }    return head;}//第二种非linus方法,创建n个元素的链表node *create_normal_2(int n){    node *head=NULL,*tail=head;    if(n>0)    {        head=(node*)malloc(sizeof(node));        printf("input number:"); scanf("%d",&head->number);        head->next=NULL;        tail=head;        --n;    }    int i;    for(i=1;i<=n;++i)    {        node *new=(node*)malloc(sizeof(node));        printf("input number:"); scanf("%d",&new->number);        new->next=NULL;        tail->next=new;        tail=new;    }    return head;}//第三种非linus方法,创建n个元素的链表node *create_normal_3(int n){    node rock,*tail=&rock;//rock作为临时栈变量,作为创建链表时的头    rock.next=NULL;        int i;    for(i=1;i<=n;++i)    {        node *new=(node*)malloc(sizeof(node));        printf("input number:"); scanf("%d",&new->number);        new->next=NULL;        tail->next=new;        tail=new;    }    return rock.next;}//linus的方法, 间接指针node *create_linus(int n){    node *head=NULL,**tail=&head;    int i;    for(i=1;i<=n;++i)    {        node *new=(node*)malloc(sizeof(node));        printf("input number:"); scanf("%d",&new->number);        new->next=NULL;        *tail=new;        tail=&new->next;    }    return head;}int main(int argc, char *argv[]){    //create list    node *head=create_normal_3(10);    print(head);    //remove list node    head=remove_list(head,rm);        printf("after rm\n");    print(head);}



remove方法不必再说,这里说下四种create_list方法。create_list在生成每一个元素时,有一个特殊的情况,那就是开始时,链表是空链表(head==NULL),该特殊情况如何考虑,如何将该特殊情况以一种顺畅的方法表达出来?如此产生了一下四种方法。
create_normal_1:
    方法1是在创建list的过程中,添加条件判断。如果链表为空,那么需要对头节点处理。如果不为空,只需要在链表结尾添加元素。
create_normal_2:
    方法2是在开始,就处理空链表的特殊情况,这种不断的从复杂逻辑中逐一分离并处理的方法很常见,也很管用。虽然保险,但是会出现"逻辑重复"的问题。
create_normal_3:
    方法3是创建一个临时的栈对象,作为list的"假开头",这样就避免了空链表这种情况。这是一种反向的思路,将多种不同逻辑整理为一种,再进一步处理。
create_linus:
    方法4既是使用Linus方法的思想,从逻辑中找到了一个共性,感觉很自然。Yes.