数据结构|双向链表|带头结点|头插|尾插|尾删|头删

简介: 数据结构|双向链表|带头结点|头插|尾插|尾删|头删

双向链表的介绍

       双向链表是一种链表,它的每个节点都有两个链接,一个指向前一个节点,另一个指向下一个节点。相比于单向链表,双向链表在插入和删除操作时更加灵活,因为它们可以从两个方向进行操作。但是,双向链表的实现比单向链表更复杂,因为需要额外的指针来维护前一个和下一个节点的链接。

尾插

       在链表的尾部插入新的结点,要插入新的结点,首先得定义一个新的结点,接这找到链表尾部结点,最后通过改变指针指向进行插入。

       先定义一个新的结点(newnode),令他的next指向NULL;

       找链表的尾部结点,定义一个移动结点tail,通过next指针进行移动,不难看出tail的next指向NULL就是链表的尾部结点

要将新结点链接到双向链表上,只需要:

将最后一个链表的结点的next指针指向newnode上,

将newnode的prev指针指向双向链表的最后一个指针上。

这样尾插就完成了,下面是代码

// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
//定义新结点
  ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
  if (newnode) {
    newnode->_data = x;
    newnode->_next = NULL;
  }
//找到最后一个结点
  ListNode* tail = pHead;
  while (tail->_next != NULL)
  {
    tail = tail->_next;
  }
//改变指针指向
  tail->_next = newnode;
  newnode->_prev=tail;
}

尾删

很简单,尾删就是删除最后一个节点将最后一个结点的位置置空:

首先应找到,最后一个结点

接着,最后一个结点的prev指向最后一个结点的前一个结点,

将前一个结点的next指向NULL((将最后一个结点的位置置空)

// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
//找到最后一个结点
  ListNode* tail = pHead;
  while (tail->_next!=NULL)
  {
    tail = tail->_next;
  }
  tail->_prev ->_next = NULL;
}

头插

       头插是在头结点的后边直接插入所以还是定一个新节点(newnode),通过改变头节点的指向,和头节点下一个结点的指向以及new结点的指向来完成头插。

       第一步先将newnode连接到链表上

       newnode->prev=pHead;

       newnode->next=pHead->next;

       因为头结点的下一个结点要通过pHead的next指针来访问,所以先不要改pHead的next的指向,否则就访问不到pHead的下一个结点了;

       要先将头结点的下一个结点的前驱结点指向newnode(pHead->next->prev=newnode)

       接着改pHead->next指针指向newnode(pHead->next=Newnode)

这样头插就完成了

// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x) 
{
  ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
  if (newnode)
  {
    newnode->_data = x;
    newnode->_next = pHead->_next;
    newnode->_prev = pHead;
        pHead->_next->_prev=newnode;
    pHead->_next = newnode;
  }
}

头删

       头删就是删除头节点的下一个结点,还是同样的原因,因为要通过next指针找下一个结点,所以应该先改蓝色的指针,(pHead->next->next->prev=pHead)

接着pHead->next=pHead->next->next;

// 双向链表头删
void ListPopFront(ListNode* pHead)
{
  pHead->_next->_next->_prev = pHead;
  pHead->_next = pHead->_next->_next;
  
}

实现:

void test3()
{
  ListNode* Dhead = ListCreate();
  ListPushBack(Dhead, 1);
  ListPushBack(Dhead, 2);
  ListPushBack(Dhead, 3);
  ListPushBack(Dhead, 4);
  printf("1到4尾插:");
  ListPrint(Dhead);
  printf("\n");
  printf("尾删一次:");
  ListPopBack(Dhead);
  ListPrint(Dhead);
  printf("\n");
  printf("尾删两次:");
  ListPopBack(Dhead);
  ListPrint(Dhead);
  printf("\n");
  printf("\n");
  ListPushFront(Dhead, 7);
  ListPushFront(Dhead, 8);
  ListPushFront(Dhead, 9);
  printf("7到9头插:");
  ListPrint(Dhead);
  printf("\n");
  printf("头删一次:");
  ListPopFront(Dhead);
  ListPrint(Dhead);
  printf("\n");
  printf("头删两次:");
  ListPopFront(Dhead);
  ListPrint(Dhead);
  printf("\n"); 
}
int main()
{
  test3();
  return 0;
}

运行结果:

相关文章
|
6天前
|
存储 Java 索引
【数据结构】链表从实现到应用,保姆级攻略
本文详细介绍了链表这一重要数据结构。链表与数组不同,其元素在内存中非连续分布,通过指针连接。Java中链表常用于需动态添加或删除元素的场景。文章首先解释了单向链表的基本概念,包括节点定义及各种操作如插入、删除等的实现方法。随后介绍了双向链表,说明了其拥有前后两个指针的特点,并展示了相关操作的代码实现。最后,对比了ArrayList与LinkedList的不同之处,包括它们底层实现、时间复杂度以及适用场景等方面。
27 10
【数据结构】链表从实现到应用,保姆级攻略
|
23天前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
|
23天前
|
存储 测试技术
【初阶数据结构篇】双向链表的实现(赋源码)
因为头结点的存在,plist指针始终指向头结点,不会改变。
|
23天前
|
存储 测试技术
【初阶数据结构篇】单链表的实现(附源码)
在尾插/尾删中,都需要依据链表是否为空/链表是否多于一个节点来分情况讨论,目的是避免对空指针进行解引用造成的错误。
|
26天前
|
算法
【数据结构与算法】共享双向链表
【数据结构与算法】共享双向链表
10 0
|
4月前
【移除链表元素】LeetCode第203题讲解
【移除链表元素】LeetCode第203题讲解
|
3月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
3月前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
3月前
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
25 2
|
4月前
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点.
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点
42 1