zoukankan      html  css  js  c++  java
  • 用二阶指针删除单向链表节点

    链表和指针的理解##

    看到CoolShell上关于Linus利用二阶指针删除单链表节点的文章,文章提到Linus大叔感叹“这个人不了解指针”,那我们又理解指针了吗?

    以下分别是文中用一阶指针和二阶指针删除单链表节点的代码:


    • 一阶指针版###

    typedef struct node {
            struct node *next;
    ...
    }node;
    
    node *remove_if(node *head, remove_fn rm) 
    {
            for (node *prev = NULL, *curr = head; curr != NULL) {
    	        node *const next = curr->next;
    		        if(rm(curr)) {
    			        if (prev)
    				        prev->next = next;
    				else
    				        head = next;
    				free(curr);	
    			} else {
    		                prev = curr;
    		        }
    			curr = next;
    	}
            return head;
    }
    
    

    • 二阶指针版###

    void remove_if(node ** head, remove_fn rm)
    {
            for (node **curr = head; *curr; ) {
                    node *entry = *curr;
                    if (rm(entry)) {
                            *curr = entry->next;
                            free(entry);
                    } else {
                            curr = &entry->next;      
                    }
            } 
    }
    

    同样是删除单向链表的节点,采用二阶指针使得代码更加简练:

    1. 对头结点不再需要特殊的判断
    2. 不需要将链表头作为返回值

    为什么呢?!CoolShell该文中提到了core low-level coding。那我们不妨从low-level来思考这个问题。

    维基百科对指针的实质是这样解释的:指针其实是一个整数

    计算机中的内存都是编址的,每个地址都有一个符号,就像家庭地址或者IP地址一样。在C语言的多数实现中,指针值等同于一个无符号整数(unsigned int,因不致歧义,下简称“整数”),它是一个以当前系统寻址范围为取值范围的整数。声明一个无符号整数并使它的值等于对象的地址值,实质上也能使之有指针的作用。

    上面的描述说明,指针提供给我们一个更贴近机器的角度,从机器的视角来看待链表:

    计算机中的内存都是编址的,每个地址都有一个符号,我们把这个符号(指针)保存下来(指针变量),组成一个序列,我们无需改变内存中的值,只需要调整这些指针变量的排列顺序,就能得到一个不同的序列;
    从这个角度看,链表不是内存单元的序列,而是内存单元指针变量的序列;也就是说,对链表的操作,本质是对指针变量的操作。


    理解了以上的文字,不妨做个小练习:用二阶指针的方法实现链表的插入(前向插入),照虎画猫,是不是很容易!下面是我的实现:

    一阶指针版本###

    typedef struct node {
    	struct node *next;
    	...
    }node;
    
    typedef node *position;
    typedef node *element;
    
    node *insert(node *head, position p, element e)
    {
        for (node prev = NULL, *curr = head; curr; ) {
                if (curr == p) {
                        if (prev) {
                                e->next = curr;
                                prev->next = e;
                                return head;
                        } else {
                                e->next = curr;
                                return e;
                        }
                } else {
                        prev = curr;
                }
                cur = cur->next;
        }    
    }
    

    二阶指针版本###

    void insert(node **head, position p, element e)
    {
        for (node **curr = head; *curr; ) {
                if (*curr == p) {
                        e->next = p;
                        *curr = e;
                } else {
                        curr = &((*curr)->next);
                }
        }
    }
  • 相关阅读:
    CachedRowSet使用
    mybatis There is no getter for property named 'xx' in 'class java.lang.String
    基于tcpdump的Android智能移动终端数据包捕获完整解决方案
    analytics详解
    android开发图片分辨率
    缩放图片,解决bitmap 内存溢出out of memory的问题
    使用windowAnimations定义Activity及Dialog的进入退出效果
    读取本地已有的.db数据库
    MyBatis 问题列表
    cxf 相关问题
  • 原文地址:https://www.cnblogs.com/joyzhuang/p/3929178.html
Copyright © 2011-2022 走看看