利用二级指针插入和删除单向链表

单链表是一种我们很常见的数据结构,在每一门介绍数据结构的书本中都会详细介绍单链表的结构和性质,单链表由一系列形如下面结构的Node节点组成

typedef struct Node{

      struct Node *next;

      int         value;

}Node;

链表最后一个节点的指针字段的值为NULL。通常我们使用一个根指针来标记链表的起始位置,通过根指针就可以访问整个链表了,根指针只是一个指针,它不含有任何数据。

上面是一个升序排列的链表。下面让我们考虑一下向链表中插入一个新节点。标准的教科书写法——插入一个结点时,需要一个previous的指针,并且这里还需要做一个边界条件的判断——current是否为链表头。于是我们有下面的代码:

     1    int insert_if(Node *current,int new_value){
     2       Node *previous;
     3       Node *new;
     4       /*find the right position by going through the list*/
     5       while(current != NULL && current->value < new_value){
     6          previous = current;
     7          current = current->next;
     8       }
     9       /*allocate memory for the new node*/
    10       new = (Node *)malloc(sizeof(Node));
    11       if(new == NULL)
    12          return FALSE;
    13       new->value = new_value;
    14    
    15       /*insert the new node into list*/
    16       new->next = current;
    17       previous->next = new;
    18       
    19       return TRUE;
    20    }

当然这段代码是有问题的,因为当在链表头插入节点时,代码将无法正确工作,为了在链表的起始位置插入一个节点,函数必须修改根指针。但是,函数不能访问变量root,因为root的值的拷贝是作为形参传递给current,任何修改都不会真正反映到root上。解决办法就是把一个指向root的指针作为参数传递给函数,这样就有下面的程序:

 1    int insert_if(Node **rootp,int new_value){
     2       Node *previous;
     3       Node *current
     4       Node *new;
     5       /*get the point of the first node*/
     6       current = *rootp;
     7       previous = NULL;
     8    
     9       /*find the right position by going through the list*/
    10       while(current != NULL && current->value < new_value){
    11          previous = current;
    12          current = current->next;
    13       }
    14       /*allocate memory for the new node*/
    15       new = (Node *)malloc(sizeof(Node));
    16       if(new == NULL)
    17          return FALSE;
    18       new->value = new_value;
    19    
    20       /*insert the new node into list*/
    21       new->next = current;
    22       if(previous==NULL)
    23          *rootp = new;
    24       else
    25          previous->next = new;
    26       
    27       return TRUE;
    28    }
         第7行赋值后,就可以用于22行判断新值是否应该被添加到链表的起始位置。上面的代码主要是针对在起始位置插入而做一些特殊处理。因为在起始位置插入新节点需要修改的指针是根指针,而对于其他节点,对指针进行的修改实际修改的是前一个节点的next自段。但事实真的是这样么?其实这两个看上去不同的操作实际上是一样的。
消除特殊情况的关键在于:链表中的每个节点都有一个指向它的指针。对于第一个节点,这个指针是根指针;对于其他节点,这个指针是前一个节点的next字段。重点在于每个指针都有一个指针指向它。至于该指针是不是位于一个节点的内部则无关紧要。

        我们拥有一个指向当前节点的指针,以及一个“指向当今节点的next字段的”指针,我们不需要previous来指示前一个节点。当移动到下一个节点时,我们保存一个“指向下一个节点的next字段的”指针,而不是保存一个指向当前一个节点的指针。如下面两幅图所示:

 

                                                               图一                  

                                                                 图二

这里rootp并不指向节点本身,而是指向节点内部的next字段。代码如下所示:

     1    int insert_if(Node **nextp,int new_value){
     2       Node *current
     3       Node *new;
     4    
     5       /*find the right position by going through the list*/
     6       while((current = *nextp) != NULL && current->value < new_value){
     7          nextp = &current->next;
     8       }
     9       /*allocate memory for the new node*/
    10       new = (Node *)malloc(sizeof(Node));
    11       if(new == NULL)
    12          return FALSE;
    13       new->value = new_value;
    14    
    15       /*insert the new node into list*/
    16       new->next = current;
    17       *nextp = new;
    18       else
    19          previous->next = new;
    20       
    21       return TRUE;
    22    }

这里分析了利用二级指针在单链表中的应用,可见其可以达到优化代码的作用,当然这一思想也可用于对链表的查找和删除,这里有一篇关于coolshell.cn/articles/8990.html 二级指针在链表中删除的应用,其思想是一样的。




  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值