初阶数据结构 带头双链表

简介: 初阶数据结构 带头双链表

一. 结构图和哨兵位


我们先来看它的结构图


5b0ff0e7d44844709cf66f8fee8d07ac.png

这里的结构大体如上


我们可以发现的是 这里其实是有一个哨兵位


那么什么是哨兵位呢?


哨兵位


我们可以把它理解成一个站岗的哨兵 它不存储值


它不参与任何的行动 只是负责站岗 标识一个唯一的头节点


二. 代码实现


我们还是跟以前一样 先创建三个工程文件


创建一个节点所需要的指针和值


struct List
{
  int val;
  struct List* prev;
  struct List* next;
};


还是和以前的类型定义一样 为了能够代码的复用 我们重定义下类型


typedef int ListNodeType;
typedef struct ListNode
{
  ListNodeType val;
  struct ListNode* prev;
  struct ListNode* next;
}LN;


这样子如果我们想要改变双链表存储的值的话只需要改变typedef的类型就可以了


三. 初始化双链表


这里很简单 我们只需要创建一个哨兵位就可以


这个哨兵位的头尾指针都要指向自身


代码表示如下


struct ListNode* InitListNode(LN* head)
{
  head = (struct ListNode*)malloc(sizeof(LN));
  head->prev = head;
  head->next = head;
  return head;
}


我们来调试下看看道理能不能初始化成功


7d9d87346a75476cb211971b46146f81.png


成功!


四. 尾插数据


我们来看图

bbd95863a1c14fd39e5197c912e8bcd3.png

首先我们需要通过tail找到一个尾


之后通过这个尾来向后插入一个新的数据


一共有四个箭头需要链接(尾2 新节点2)


在实现这个函数之前我们首先先来写一个创造新节点的函数


struct ListNode* BuyListNode()
{
  struct ListNode* newnode = (struct ListNode*)malloc(sizeof(struct ListNode));
  return newnode;
}


代码表示如上


之后我们开始找尾 插入数据


代码表示如下


void ListNodePushBack(LN* head, ListNodeType x)
{
  assert(head);
  struct ListNode* newnode = BuyListNode();
  struct ListNode* tail = head->prev;
  newnode->val = x;
  tail->next = newnode;
  newnode->prev = tail;
  head->prev = newnode;
  newnode->next= head;
}

五. 打印数据


没有什么难度


代码表示如下


void ListNodePrint(LN* head)
{
  assert(head);
  struct ListNode* cur = head->next;
  while (cur!=head)
  {
    printf("%d-> ", cur->val);
    cur = cur->next;
  }
  printf("NULL");
}


接下来我们试试看打印尾插的数据


fa809d39c8f249beae6dfcbff2b5efd6.png


我们发现没有问题


六. 尾删数据

f506de7510554728b28290542a39ba6e.png

首先我们需要找到tail之前的一个数据 我们将这个数据称之为prev


然后按照上图链接就可以


但是又一种特殊情况 如果说 head 既是头又是尾 我们这里就需要报错


因为哨兵位不可以删除


代码表示如下


void ListNodePushBack(LN* head)
{
  assert(head);
  assert(head->next != head);
  struct ListNode* tail = head->prev;
  struct ListNode* prev = tail->prev;
  prev->next = head;
  head->next = prev;
  free(tail);
}


然后效果表示如下


9b3141301f4a4b0f807bd72f8c6e81e8.png


七. 头插数据


还是一样 我们先看图


0bd83a122a134c4ab2f0cb3196cfe34c.png

代码表示如下


void ListNodePushFront(LN* head, ListNodeType x)
{
  assert(head);
  struct ListNode* Phead = head;
  struct ListNode* Next = head->next;
  struct ListNode* newnode = BuyListNode();
  newnode->val = x;
  Phead->next = newnode;
  newnode->prev = Phead;
  newnode->next = Next;
  Next->prev = newnode;
}


显示效果如下


183ba06942454521ab784bde863b3a78.png


八. 头删数据

9b4f9c0befdc42f88c344834db0e3f0b.png我们发现要头删除数据的话要使用三个指针


哨兵位指针


头指针


头指针的下一位


开始写代码


void ListNodePopFront(LN* head)
{
  assert(head);
  assert(head->next != head);
  LN* Phead = head->next;
  LN* Next = Phead->next;
  head->next = Next;
  Next->prev = head;
  free(Phead);
}


显示效果如下


a5bf2604963b40cea3dee9a068e7bbe9.png


九. 查找指定位置


这个实现起来也很简单 跟打印的思路差不多


struct ListNode* ListNodeFindPos(LN* head, ListNodeType x)
{
  assert(head);
  struct ListNode* cur = head->next;
  while (cur!=head)
  {
    if (cur->val == x)
    {
      return cur;
    }
    cur=cur->next;
  }
  return NULL;
}


如果找到return pos的位置


如果找不到我们就返回一个空指针


十. 指定位置前插入数


如图


1cb4c7215fd64bc3966c634cbd9670a5.png

看图敲代码


void ListNodeInsertPos(LN* Pos,ListNodeType x)
{
  assert(Pos);
  LN* Prev = Pos->prev;
  LN* newnode = BuyListNode();
  newnode->val = x;
  Prev->next = newnode;
  newnode->prev = Prev;
  newnode->next = Pos;
  Pos->prev = newnode;
}


我们来看看效果


f75415e0cd874e119bfc41464d758481.png


十一. 删除指定位置的数


还是一样 先看图

a215a8a969544811b988359b86555685.png


这里我们需要三个指针 一个前面的一个后面的


但是这里我们需要注意


Pos指针不能为空


并且Pos指针不能指向头节点


我们来看看代码


void ListNodeEasePos(LN* Pos)
{
  assert(Pos);
  assert(Pos->next != Pos->prev);
  LN* Prev = Pos->prev;
  LN* Next = Pos->next;
  Prev->next = Next;
  Next->prev = Prev;
  free(Pos);
}


我们再看看效果图怎么样

f41d8417b57c4fcd914c755606b58678.png


以上就是本篇博客的全部内容啦 由于博主才疏学浅 所以难免会出现纰漏


希望大佬们看到错误之后能够不吝赐教 在评论区或者私信指正 博主一定及时修正


那么大家下期再见咯


相关文章
|
7天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
31 4
|
8天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
8天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
29天前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
24 7
|
29天前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
22 3
|
27天前
|
算法 Java
数据结构与算法学习五:双链表的增、删、改、查
双链表的增、删、改、查操作及其Java实现,并通过实例演示了双向链表的优势和应用。
15 0
数据结构与算法学习五:双链表的增、删、改、查
|
7天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
24 0
【数据结构】——双向链表详细理解和实现
【数据结构】——双向链表详细理解和实现
|
1月前
|
存储 Java
【数据结构】链表
【数据结构】链表
16 1
|
1月前
|
存储 缓存
数据结构3——双向链表
数据结构3——双向链表
108 1