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

看到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.

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值