双向链表的基本操作

   学过单向链表的小伙伴都知道单向链表中的每一个节点有且只有一个指针,这个指针就是用来指向下一个节点的,单向链表顾名思义就是链表方向是单方向的,而本文要介绍的双向链表就是链表方向是双方向的,也就是双向链表中的每一个节点有两个指针,一个指针用来指向上一个节点(前驱),另一个指针用指向下一个节点(后继)。

  本文主要是总结一下自己对双向链表的基本操作,当然我也只是写了几个比较简单的操作,其中包括双向链表的创建,插入节点,删除节点,还有输出节点的数据等。学习这个双向链表总的感受就是特别绕,因为涉及多个指针的操作,对于指针没有学好的人儿来说,理解双向链表还是比较困难的。不过功夫不负有心人,只要肯花时间,我觉得一切都不是问题的。下面贴上自己写的代码:

/*********************************************************************************
 *      Copyright:  (C) 2017 zoulei
 *                  All rights reserved.
 *
 *       Filename:  link.c
 *    Description:  This file
 *
 *        Version:  1.0.0(2017年07月26日)
 *         Author:  zoulei <zoulei121@gmail.com>
 *      ChangeLog:  1, Release initial version on "2017年07月26日 18时51分00秒"
 *
 ********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct DoubleLinkNode
{
   int data;
   struct DoubleLinkNode *prev;
   struct DoubleLinkNode *next;
}Node;
 /* 创建一个带头节点的双向链表 */
Node*Create_Double_link()
{
   Node*head;
   Node*pnext;
   Node*plast;
   int i,n;
   head=(Node*)malloc(sizeof(Node));
   assert(NULL != head);
   head->prev=NULL;
   head->next=NULL;

   printf("please input the length of the double linked list:");
   scanf("%d",&n);
   while(n!=0)
   {
      plast=head;
      for(i=0;i<n;i++)
      {
         pnext=(Node*)malloc(sizeof(Node));
         printf("向第%d个节点输入数据:",i+1);
         scanf("%d",&pnext->data);
         plast->next=pnext;
         pnext->prev=plast;
         plast=plast->next;
      }
      pnext->next=NULL;
      break;
   }
   return head;
}
/* 输出每一个节点的数据 */
void print(Node*head)
{
  Node*temp;
  int j=0;
  temp=head;
  while(temp->next!=NULL)
  {
     j++;
     printf("输出第%d个节点的数据:%d\n",j,temp->next->data);
     temp=temp->next;
  }
  printf("输出第%d个节点的数据:%p\n",j+1,temp->next);
}
/* 插入节点 */
int InsertNode(Node* head)
{
   Node*new;
   Node*pnext=head;
   int i=0;
   int n;

   printf("please input the location which is inserted:");
   scanf("%d",&n);

   while((i<n) && (pnext!=NULL))
   {
      i++;
      pnext=pnext->next;

   }
   if(pnext==NULL)
   {
     return 1;
   }
   else
   {
        new=(Node*)malloc(sizeof(Node));
        printf("请在新插入的节点中输入数据:");
        scanf("%d",&new->data);

        new->next=pnext->next;
        if(n=0)
        {
          pnext->next=new;
          new->next=NULL;
        }
        else
        {
          pnext->next=new;
          pnext->next->prev=new;
          new->prev=pnext;
        }
   }
   return 0;
}
/*删除节点 */
int DeleteNode(Node*head)
{
   Node*pnext=head;
   Node*ptr;
   int n;
   int i=0;
   printf("please input the node that you will delete:");
   scanf("%d",&n);
   while((i<n-1) && (pnext!=NULL))
   {
      i++;
      pnext=pnext->next;
   }
   if(pnext->next->next!=NULL)
   {
       ptr=pnext->next;
       ptr->next->prev=pnext;
       pnext=ptr->next;
       free(ptr);
   }
   else
   {
     ptr=pnext->next;
     free(ptr);
   }
  return 0;
}
 /* 主函数 */
int main(int argc,char**argv)
{
   Node* head;
   head=Create_Double_link();
   InsertNode(head);
   DeleteNode(head);
   print(head);
   return 0;
}

代码分析:

1.创建原链表如图所示:



头节点的一个指针初始化时指向NULL,分析一下核心代码吧!plast是我定义的一个临时指针,通过这个临时指针将所有节点连接起来,首先将plast指向头结点,pnext是指向新增节点的指针,所以用plast->next指向新增节点,新增节点的pnext->prev指向前一节点,由于是新增第一个节点,所以第一个节点也就指向头结点,而头节点的head->next指向第一个节点,最后再将临时指针指向第一个节点,这样不断的循环下去,就可以创建指定长度的链表了。不过最后一个节点指向下一个节点的指针必须赋值为为NULL,对应代码就是源文件中的 pnext->next=NULL;

2.在原链表的指定位置插入一个节点,如下图:


这里在原链表的指定位置插入一个节点,整体思想是:先循环遍历到要插入的位置,再把插入的节点的一个指针用来指向下一个节点,即将插入的节点的另一个指针指向上一个节点,不过首先要把插入的那个位置的节点与之相连的下一个节点断开。代码怎么来实现这个逻辑呢?假设以上图为例,我的目的是想在第一个节点与第二个节点之间插入一个新的节点,代码实现是这样的:首先用一个while循环遍历到第一个节点的位置,然后用一个指针pnext指向第一个节点,pnext->next指针就是指向第二个节点,然后new是一个指向新增节点地址的指针,在我们要断开第一个节点与第二个节点之前,用新增节点的指针new->next指向第二个节点的地址,这样后面我们才能操作第二个节点的地址,也就是对应 new->next=pnext->next;这段代码;接着将原先指向第二个节点的指针pnext->next指向新增节点的地址也就是指向new;然后将原先指向第一个节点的指针pnext->next->prev现在改为指向新增节点的地址(new是指向新增节点的内存地址的指针,这里prev指向new也就指向了新增节点的内存地址);最后将新增节点的另一个指针prev指向第一个节点的地址,这样就将第一个节点与第二个节点断开了,同时也将新节点插入到了指定位置。

3.删除原链表中指定的节点,如图所示:


删除指定节点过程也就是插入指定节点的逆过程。看图就明白了,这里就不分析了。

测试结果(只贴上删除节点的):










  • 30
    点赞
  • 121
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值