有序双链表的插入问题

来源:互联网 发布:mac网站上传工具 编辑:程序博客网 时间:2024/05/19 03:21

最近两天看《C和指针》这本书的链表部分(第十二章),感觉作者写得实在是太棒了,C指针用得太漂亮了。自己看完后稍微有点心得,记录在此以便日后复习。
这里只讨论双链表(Doubly Linked List),更具体的说是有序双链表的插入问题
所谓双链表,就是链表中每个节点含两个节点类型的指针,一个指向下一个节点,另外一个指向上一个节点。
链表节点数据结构定义如下:

typedef struct NODE{  struct NODE *fwd;// forward---pointer to the next     node in the list  struct NODE *bwd;//backward---pointer to the previous node in the list  int value;} Node;

如上图所示,根节点的fwd指向链表中第一个节点,第一个节点的fwd指向第二个节点,以次类推,注意最后一个节点的fwd指向NULL;最后一个节点的bwd指向前一个节点,以此类推,注意第一个节点的bwd指向NULL;此外,要注意根节点的bwd也是指向最后一个节点的。

这样,我们可以从两个方向来遍历双链表的节点,使得链表操作更加方便快捷。

对于有序双链表的插入问题,第一步就是要找到新节点的插入位置。

Node *this,*next,*new_node;for(this=root;(next=this->fwd)!=NULL;this=next){   if(next->value==new_value)       return 1;    if(next->value > new_value)        break;}

上面是书中寻找新节点插入位置的代码。程序的意思是把new_node插入到this和next指向的节点中间,但是不插入链表中已存在的数值。


新节点插入位置分析:

1)最一般的情况就是将新值插入到链表的中间了,如下图所示:


插入新节点后的链表示意图如下:


代码实现:

    this->fwd=new_node;new_node->fwd=next;    next->bwd=new_node;new_node->bwd=this;

分析问题时要注意边界情况,往往这也是特殊情况出现的地方。


2)在链表起始位置插入新节点


插入新节点后的链表示意图如下:


代码实现:

    this->fwd=new_node;new_node->fwd=next;    next->bwd=new_node;new_node->bwd=NULL;

有一点请务必注意:在这种情况下,有

root=this;


3)在链表的末端插入新节点

插入新节点后的链表示意图如下:

代码实现:

    this->fwd=new_node;new_node->fwd=NULL:new_node->bwd=this;    root->bwd=new_node;

有一点请务必注意:

在这种情况下,有next=NULL;


4)还有一种更特殊的情况-原链表是空的

插入新节点后的链表示意图如下:

代码实现:

    this->fwd=new_node;new_node->fwd=NULL;new_node->bwd=NULL;    this->bwd=new_node;

有一点请务必注意:

在这种情况下,有

next=NULL;

this=root;


插入新节点的实现代码

1)自己的代码实现

/*malloc a new node for the would-be insertion */  new_node=(Node *)malloc(sizeof(Node));  if(!new_node){  printf("malloc new node error!\n");        exit(2);   }   new_node->value=new_value;              if(!this->fwd){//the list is empty before insertion           this->fwd=new_node;       new_node->fwd=NULL;      new_node->bwd=NULL;           this->bwd=new_node;   } else if(!next->bwd){//insert to the right position after root                  this->fwd=new_node;      new_node->fwd=next;           next->bwd=new_node;      new_node->bwd=NULL;      } else if(!next->fwd){//insert in the end              this->fwd=new_node;     new_node->fwd=NULL:    new_node->bwd=this;         root->bwd=new_node;      } else{//insert in the middle of list                this->fwd=new_node;     new_node->fwd=next;         next->bwd=new_node;    new_node->bwd=this;  }

我自己写的代码也能实现插入新节点的功能,但是呢,太冗余了。

2)书中的代码分析及实现

New node insertion position 

Code implementation

notes

middle

1) this->fwd=new_node;

2)new_node->fwd=next;   

3)next->bwd=new_node;

4)new_node->bwd=this;

start

 1)this->fwd=new_node; 

2)new_node->fwd=next; 

3)next->bwd=new_node; 

4)new_node->bwd=NULL;

root=this; 

 end

1)this->fwd=new_node; 

2)new_node->fwd=NULL:

 3)new_node->bwd=this;

 4)root->bwd=new_node;

next=NULL;

empty list

1)this->fwd=new_node; 

2)new_node->fwd=NULL;

 3)new_node->bwd=NULL; 

4)this->bwd=new_node;

next=NULL;

this=root;

请仔细观察这个表格:

1.四种情况下第一、第二行代码是完全一样的。
对于endempty两种情况,请注意notesnext=NULL
---这个启示我们可以把第一、第二行代码从ifelse语句中抽取出来,放在ifelse语句之前。

2.emptyend两种情况下的第四行代码是一样的,即this->bwd=new_node,因为在empty情况下this=root;
 而middlestart两种情况下第三行代码是一样的,即next->bwd=new_node;
在这儿可以发现:
this->bwd=new_node
next->bwd=new_node;
区别在于thisnext。因此我们寻找一个判别条件来判断到底是取
this->bwd=new_node;还是next->bwd=new_node
再观察notes列,对于emptyendnext=NULL;而对于middlestartnext!=NULL,
因此next是否等于NULL便是判断条件。

if(next==NULL)   this->bwd=new_node;else    next->bwd=new_node;

3.对于start的第四行代码和empty的第三行代码是一样的,即new_node->bwd=NULL;
middle的第四行和end的第三行代码是一样的,即new_node->bwd=this
观察notes可知this是否等于root便可作为判断条件。

if(root==this)   new_node->bwd=NULL;else    new_node->bwd=this;

综上所述,完整代码如下:

//the following method is from the book with little change.int dll_insert(Node *root,int new_value){       Node *this,*next,*new_node;    for(this=root;(next=this->fwd)!=NULL;this=next){        if(next->value==new_value)            return 1;        if(next->value > new_value)            break;    }    new_node=(Node *)malloc(sizeof(Node));    if(!new_node){        printf("malloc new node error!\n");        return -1;    }    new_node->value=new_value;    new_node->fwd=next;    this->fwd=new_node;   if(root==this)        new_node->bwd=NULL;    else        new_node->bwd=this;    if(next==NULL)        root->bwd=new_node;    else        next->bwd=new_node;        root->value++;       return 1;  } 

但愿自己表述清楚了,希望自己没有使用错别字。
欢迎大家批评指正!