您的位置:首页 > 其它

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

2014-01-17 12:58 316 查看
单链表是一种我们很常见的数据结构,在每一门介绍数据结构的书本中都会详细介绍单链表的结构和性质,单链表由一系列形如下面结构的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 = ¤t->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 二级指针在链表中删除的应用,其思想是一样的。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息