有序双链表的插入问题

最近两天看《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;  
} 

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coffee_baba

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值