• linus提到过的单链表删除节点算法


    linus 提到过的单链表删除节点算法

    1 问题描述

    在TED上做过一次访谈,linus提到了关于编程的品味,他举了一个例子:

    linus在TED演讲_哔哩哔哩_bilibili

    见原视频15'前后

    image-20210912231607546

    解法1

    image-20210912231634945

    解法2

    这个例子要删掉一个链表的节点项

    传入的参数是一个节点的引用

    解法1,使用了prev

    remove_list_entry(entry)
    {
        prev = NULL;
        walk = head;
        while (walk && walk!=entry)
        {
            prev = walk;
            walk = walk->next;
        }
        
        // Remove the entry by
        // updating the head or previous entry
        if (!prev)
        {
            head = entry->next;
        }
        else
        {
            prev->next = entry->next;
        }
        
        // 释放节点空间
        free(entry);
    }
    

    解法2,使用了二重指针

    remove_list_entry(entry)
    {
        // The "inderect" pointer points to the
        // *address* of of the thing we will update
        indirect = &head;
        
        // Walk the list, looking for the thing that points to
        // entry we want to remove entry
        while ((*indirect)&&(*indirect)!=entry)
        {
            indirect = &(indirect->next);
        }
        
        // just remove the entry
        *indirect = entry->next;
        free(entry);
    }
    

    2 思路

    解法1,是常用的解法

    一般情况

    用一个前驱节点 prev 来寄存待删除节点之前的节点

    用图形表示就是

    image-20210912234134071

    这样,就能实现将prev指向entry的后继节点

    特殊情况

    为了保证可靠性,也需要考虑到

    • 整个链表只有2个节点的情况

    image-20210912234642850

    此时需要我们判断 prev=NULL

    并让head->next直接指向entry->next

    • 整个链表只有1个节点的情况

    image-20210912234842119

    此时可能需要直接释放 head 所指向的节点空间

    并让head指向NULL

    解法2

    二重指针

    指针是一次寻址

    二重指针是二重寻址

    indirect=&head

    head本身是指向一个节点的指针,而indirect存储了head的地址,所以是存储指针的容器

    这里不得不提到节点的定义

    typedef struct ListNode
    {
        ListNode* next;
        int data;
    } ListNode;
    

    每个节点其实都存储了

    1. 下一个节点的地址
    2. 本身数据

    大概类似这样

    image-20210912235331628

    注意我在上面加了一个地址0x0000000

    其实next的内容,就是地址,指针就是保存了地址的变量。

    那么把整个链表放在一起看,是这样的:

    image-20210912235953020

    每个节点的next字段,都保存了它下一个节点的地址

    那么,我们可以认为,每个节点的next字段就是一个指针变量

    而 indirect = &head

    就是一个二重指针

    indirect存放了head的地址

    可以通过解引用运算获取head里面的值

    具体操作

    那么,究竟如何完成删除一个节点的功能?

    image-20210913000939965

    为了方便叙述,给每个next字段都加上一个地址 ,分别记作ABCD

    假设我们要删掉0x00000008这个节点

    此时indirect已经指向head了

    while (*indirect && *indirect != entry)
    {
        indirect = &(*indirect->next);
    }
    

    这段循环,让indirect指向了 存放entry地址 的next字段

    即此时 indirect = B

    此时,如果让B里面的内容,从0x00000008变为0x00000010

    就能完成删除节点,维护链表的操作

    代码如下

        // just remove the entry
        *indirect = entry->next;
        free(entry);
    

    示意图

    image-20210913001200419

    特殊情况处理

    像其他的情况,如

    • 只有2个节点,head节点和entry节点
    • 只有entry节点(即entry节点就是head节点)

    也可以很好的解决,如有兴趣可以自己实现一下。

    对编程的爱好,让我充满力量,加油!

  • 相关阅读:
    续上-选课系统
    第一个java web的课堂练习-开始
    子类与父类方法间的关系
    课后作业-3
    小结
    Java中子类与基类变量间的赋值
    今日总结
    今日总结
    今日总结
    今日总结
  • 原文地址:https://www.cnblogs.com/studentWangqy/p/15260743.html
Copyright © 2020-2023  润新知