使用二级指针简化臃肿的代码

单链表的删除简直就是最最基础的知识了,从大二上数据结构到今天我一直都记得如果要删除单链表,那就一定要判断是不是头结点,教科书都是这么教我们的,简单写个例子

while(cur->next->value != key)
    cur = cur->next;
if(cur == head)
    //头结点
else
    //不是头结点
    cur->next = cur->next->next;
    free();

这段代码已经深深的印在了我的脑子里

删除单链表要使用它的pre指针作为判断,并且要考虑头结点的问题
意思就是我们在做删除的时候要拿到它的pre,但是这是单链表没有pre指针,所以需要我们对代码有些处理,使用
cur->next->value != key

这我相信是大部分人的思路,也是教科书的思路。这样做不好的地方在哪里,在比如你在定义二叉查找树的时候

typedef struct binary_search_tree
{
    int value;
    struct binary_search_tree *lchild;
    struct binary_search_tree *rchild;
}tree_t;

左孩子和右孩子都使用同一个pre,那就更别提B树了。这样带来的麻烦就是:在(以二叉查找树为例)删除操作时,你要多考虑很多种问题,你需要记录应该删除节点的pre指针,还要判断是lchild还是rchild,同时还需要判断是不是头结点。我实现了删除的代码,看看有多长

void delete(tree_t *bs_tree,tree_t **bs_parent,int index)
{
    tree_t *p,*t;
    if (bs_tree->rchild == NULL)
    {
        if (index == 0)
        {
            (*bs_parent)->lchild = bs_tree->lchild;
            bs_tree->lchild = NULL;
            free(bs_tree);
        }
        else if (index == 1)
        {
            (*bs_parent)->rchild = bs_tree->lchild;
            bs_tree->lchild = NULL;
            free(bs_tree);
        }
        else
        {
            *bs_parent = bs_tree->lchild;
            free(bs_tree);
        }
    }
    else if (bs_tree->lchild == NULL)
    {
        if (index == 0)
        {
            (*bs_parent)->lchild = bs_tree->rchild;
            bs_tree->rchild = NULL;
            free(bs_tree);
        }
        else if (index == 1)
        {
            (*bs_parent)->rchild = bs_tree->rchild;
            bs_tree->rchild = NULL;
            free(bs_tree);
        }
        else
        {
            *bs_parent = bs_tree->rchild;
            free(bs_tree);
        }
    }
    else
    {
        p = bs_tree;
        t = bs_tree->lchild;

        while(t->rchild != NULL)
        {
            p = t;
            t = t->rchild;
        }

        if (p == bs_tree)
        {
            t->rchild = p->rchild;
            p->rchild = NULL;
            if (index == 0)
            {
                (*bs_parent)->lchild = t;
            }
            else if (index == 1)
            {
                (*bs_parent)->rchild = t;
            }
            else
            {
                (*bs_parent) = t;
            }
        }
        else
        {
            bs_tree->value = t->value;
            p->rchild = NULL;
            free(t);
        }
    }
}

void delete_value(tree_t *bs_tree,int key,tree_t **bs_parent,int index)
{
    if (bs_tree->value < key)
    {
        bs_parent = &bs_tree;
        delete_value(bs_tree->rchild,key,bs_parent,1);
    }
    else if (bs_tree->value > key)
    {
        bs_parent = &bs_tree;
        delete_value(bs_tree->lchild,key,bs_parent,0);
    }
    else
    {
        if (index == 1 || index == 0)
        {
            delete(bs_tree,bs_parent,index);
        }
        else
            delete(bs_tree,bs_parent,-1);
    }
}

index 0表示左孩子,1表示右孩子,如果-1就是根节点。当然没有注释是因为我不希望你像我这么傻乎乎的做,你只需要知道你要考虑很多可能就好了。
多写一行代码就有一定的概率出错,于是我看到了这篇文章
http://coolshell.cn/articles/8990.html

一开始我是拒绝的。我觉得这不可能完成,这不对,即使二级指针也不能改变pre中的next的地址啊!!

那么我们看一个简单的例子吧

    int **p;
    int *b = malloc(sizeof(int));
    *b = 5;
    p = &b;
    **p = 3;
    printf("%d \n",*b );

应该输出几呢,3!这就是使用二级指针修改的核心原理。

这样,删除链表就这样了

void test_fun(link_t **l,int key)
{
    link_t **cur = l;
    link_t *entry = *cur;
    while(entry->value != key)
    {
        cur = &entry->next;
        entry = *cur;
    }

    (*cur) = entry->next;
    free(entry);
}

那么我上面的删除二叉查找树的代码就可以精简很多了。我不用考虑是不是左、右孩子,也不用考虑是不是根节点!肯定能让代码逻辑性更强的。

今天这份代码基本刷新了我对单链表的认识。。同样的功能可以如此优雅,也可以臃肿不堪:)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值