双链表(Double Linked LIst)

双链表


双链表属于链表的一种,有两个指针域,分别指向直接后继和直接前驱。所有在遍历双向链表时,从任意一个节点开始,都可以很方便的访问它的前驱节点和后继节点。使用这种方式解决了单链表中不能使用反向遍历的问题。

节点数据结构


在双链表中,每个节点包含三个部分:

  • 指向当前节点上一个节点的指针
  • 当前节点存储数据的数据域
  • 指向当前节点下一个节点的指针
struct Node{
    int data;
    struct Node *previous,*next;
} *head=NULL;

节点的运算形式


基本的运算形式:增加、删除、更新

插入节点到序列尾部

创建一个新的节点,通过遍序列表到序列末尾,让后将节点插入到末尾。

插入过程
  1. 创建一个新节点并赋值,将Node的next指针设置为NULL
  2. 检查集合的头节点是否为空(head==NULL)
  3. 如果头节点为空,设置newNode->previous=NULL,head=newNode;
  4. 如果头节点不为空,定义一个临时节点temp=head;
  5. 移动temp节点直到到达序列的尾部
  6. 设置newNode=temp->next和temp=newNode->previous;
void insertAtENd(int value){
    struct Node *newNode;
    newNode=(struct Node*)malloc (sizeof(struct Node));
    newNode->data=value;
    newNode->next=NULL;
    if (head==NULL){
        newNode->previous=NULL;
        head=newNode;
    }else{
         struct Node *temp = head;
      while(temp -> next != NULL)
         temp = temp -> next;
      temp -> next = newNode;
      newNode -> previous = temp;
    }
    printf("插入末尾成功");
}
插入节点到头部

创建一个新的节点,将头节点替换为新的节点,并更新指针的指向。

插入过程
  1. 创建一个新的节点newNode,并设置newNode->previous=NULL;
  2. 检查是否head==NULL;
  3. 如果head==NULL,newNode->next=NULL,head=newNode;
  4. 如果head!=NULL,newNode->next=head,head=newNode;
void insertAtBeginning(int value){
    struct  Node *newNode;
    newNode=(struct Node*)malloc(sizeof(struct Node));
    newNode->data=value;
    newNode->previous=NULL;
    if (head==NULL){
        newNode->next=NULL;
        head=newNode;
    }else{
        newNode->next=head;
        head->previous=newNode;
        head=newNode;
    }
    printf("插入成功");
}
插入节点到指定元素后

循环遍历链表,创建一个新的节点,然后将其插入到链表中的指定位置

插入过程
  1. 创建一个新节点并赋值
  2. 检查链表是否为空(head==NULL)
  3. 如果(head==NULL),newNode->previous=NULL,newNode->next=NULL,head=newNode
  4. 定义一个temp=head
  5. 通过循环遍历移动temp节点,指定找到我们需要插入的节点位置(for循环到position-1)
  6. 如果temp->next==NULL设置flag=0,表面我们要查找的目标元素未发现,终止循环
  7. 如果flag=1,设置newNode->next=temp->next,temp->next->previous=newNode,temp->next=newNode和newNode->previous=temp;
void insertAfter(int value, int pos)
{
   int i, flag = 1;
   struct Node *newNode, *temp = head;
   newNode = (struct Node*)malloc(sizeof(struct Node));
   newNode -> data = value;
   if(head == NULL)
   {
      newNode -> previous = newNode -> next = NULL;
      head = newNode;
   }
   else
   {
    for (i = 0; i < pos - 1; i++) {
        temp = temp -> next;
        if (temp -> next == NULL) {
            flag = 0;
            break;
        }
    }

    if (flag) {
        newNode -> next = temp -> next;
        temp -> next -> previous = newNode;
        temp -> next = newNode;
        newNode -> previous = temp;
        printf("\nInsertion successful\n");
    }
    else
        printf("Number of elements is less than position entered");
   }
}
从链表尾部删除节点

通过循环遍历到链表尾部,删除尾部节点

从尾部删除过程
  1. 检查链表是否为空(head==NULL)
  2. 如果为空,抛出错误并终止程序
  3. 如果不为空,定义一个temp=head;
  4. 检查是否链表只存在一个节点(temp->previous=NULL和temp->next=NULL)
  5. 如果只存在一个节点,设置head=NULL并删除temp节点
  6. 如果链表存在多个节点,移动temp节点直到到达链表尾部(temp->next!=NULL)
  7. 设置temp->previous->next=NULL并释放temp占用内存(free(temp))
void deleteEnd()
{
   if(head == NULL)
      printf("链表为空");
   else
   {
      struct Node *temp = head;
      if(temp -> previous == temp -> next)
      {
         head = NULL;
         free(temp);
      }
      else{
         while(temp -> next != NULL)
            temp = temp -> next;
         temp -> previous -> next = NULL;
         free(temp);
      }
      printf("\n删除成功");
   }
}
从链表头部删除节点

从链表头部删除节点

从头部删除过程
  1. 检查链表是否为空(head==NULL)
  2. 如果为空,抛出异常并终止
  3. 如果不为空,定义一个temp节点,且temp=head
  4. 检查链表是否只有一个节点(temp->previous=temp->next)
  5. 如果链表只有一个节点,设置head=NULL并释放free(temp)
  6. 否则,设置temp->next=head,head->previous=NULL并释放free(temp)
void deleteBeginning()
{
   if(head == NULL)
      printf("链表为空");
   else
   {
      struct Node *temp = head;
      if(temp -> previous == temp -> next)
      {
         head = NULL;
         free(temp);
      }
      else{
         head = temp -> next;
         head -> previous = NULL;
         free(temp);
      }
      printf("\n删除成功");
   }
}
从链表指定位置删除节点

遍历链表到找到指定节点

从指定位置删除过程
  1. 检查链表是否为空(head==NULL)
  2. 如果为空,抛出错误并终止
  3. 如果不为空,定义一个temp,且temp=head
  4. 移动temp节点,直到找到目标节点或者到达链表末尾
  5. 如果到达节点末尾,抛出未发现目标节点异常,并终止
  6. 如果到达目标节点,检查是否只有一个节点
  7. 如果仅有一个节点,设置head=NULL并释放free(temp)
  8. 如果链表有多个节点,检查是否为头节点(temp==head)
  9. 如果为头节点(temp=head),将头节点移动到下一个节点(head==head->next),设置head->previous=NULL并释放内存free(temp)
  10. 如果temp!=head,检查temp是否为最后一个节点(temp->next==NULL)
  11. 如果为最后一个节点,设置temp->previous->next=NULL并释放free(temp)
  12. 如果temp不是第一个节点也不是最后一个节点,设置temp->previous-next=temp->next,temp->next->previous=temp->previous并释放free(temp)
void deleteSpecific(int delValue)
{
   if(head == NULL)
      printf("List is Empty");
   else
   {
      struct Node *temp = head;
      while(temp -> data != delValue)
      {
         if(temp -> next == NULL)
         {
            printf("\nGiven node is not found in the list");
         }
         else
         {
            temp = temp -> next;
         }
      }
      if(temp == head)
      {
         head = NULL;
         free(temp);
      }
      else
      {
         temp -> previous -> next = temp -> next;
         free(temp);
      }
      printf("\nDeletion successful");
   }
}

双连边的应用常见


  1. 浏览器的历史纪录 大多数主流浏览器都支持针对浏览历史记录的前进、后退,就是基于双链表设计的
  2. 大多数算法
  3. 游戏:卡牌游戏,记录牌的顺序

更多内容,欢迎关注:


在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值