带头双向循环链表的增删改查
创始人
2024-05-04 00:34:46
0次

目录

  • 🤡前言
  • 😊带头双向循环链表
  • 👍链表实现
    • 😠插入-头插,尾插,随机插
    • ✅删除-头删,尾删,随机删
    • 😂链表搜索和链表修改
  • 💡总结


🤡前言

本篇博客主要是介绍带头双向循环链表的一些基本的增删改查的操作。

😊带头双向循环链表

在这里插入图片描述
如上图所示,我们所说的带头双向循环链表常指的是带有哨兵位头节点head,前一个结点的尾指针指向后一个节点,后一个节点的头指针指向前一个节点,并且最后一个节点的尾指针指向哨兵位节点,哨兵位节点的头指针指向最后一个节点,这就是双向带头循环链表。

👍链表实现

要实现带头双向循环链表,我们首先就需要创建出该相应的结构体。

typedef int LTDataType;
typedef struct ListNode
{LTDataType _data;struct ListNode* _next;struct ListNode* _prev;
}ListNode;

之后我们创建这个链表的哨兵位头节点并返回,我们用ListCreate()函数实现,如下代码。

	ListNode* ListCreate()
{ListNode* head = (ListNode*)malloc(sizeof(ListNode));head->_data = 0;head->_next = head;head->_prev = head;return head;
}

😠插入-头插,尾插,随机插

接下来就是对带头双向循环链表的插入,插入可以分为头插,尾插和随机插,我们用三个函数来实现。我们先进行头插ListPushFront(ListNode* pHead, LTDataType x);,如下代码。

ListNode* BuyNode(LTDataType x)
{ListNode* new = (ListNode*)malloc(sizeof(ListNode));new->_data = x;new->_next = NULL;new->_prev = NULL;return new;
}
void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* p = BuyNode(x);p->_next = pHead->_next;pHead->_next->_prev = p;p->_prev = pHead;pHead->_next = p;
}

接下来我们进行尾插,尾插我们用函数ListPushBack(ListNode* pHead, LTDataType x);来实现,如下代码。

ListNode* BuyNode(LTDataType x)
{ListNode* new = (ListNode*)malloc(sizeof(ListNode));new->_data = x;new->_next = NULL;new->_prev = NULL;return new;
}
void ListPushBack(ListNode* pHead, LTDataType x)
{ListNode* p = BuyNode(x);ListNode* ret = pHead->_prev;p->_next = pHead;ret->_next = p;p->_prev = ret;pHead->_prev = p;
}

无论是头插还是尾插,只要我们找准哨兵位节点,谨慎使用好哨兵位节点的各个指针,就可以很简单的完成带头双向循环链表的头插和尾插。在完成头插和尾插后,最后我们还剩下一个随机插函数,随机插入我们用ListInsert(ListNode* pos, LTDataType x);函数完成,如下代码。

ListNode* BuyNode(LTDataType x)
{ListNode* new = (ListNode*)malloc(sizeof(ListNode));new->_data = x;new->_next = NULL;new->_prev = NULL;return new;
}
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* p = BuyNode(x);p->_next = pos;p->_prev = pos->_prev;pos->_prev->_next = p;pos->_prev = p;
}

✅删除-头删,尾删,随机删

跟前面的插入一样,删除我们也有3种删除方式,分别是头删,尾删和随机删,接下来我们会一一将代码放出来。头删我们用函数ListPopFront(ListNode* pHead);来完成,代码如下。

void ListPopFront(ListNode* pHead)
{assert(pHead);ListNode* p = pHead->_next;p->_next->_prev = pHead;pHead->_next = p->_next;free(p);
}

尾删我们用函数ListPopBack(ListNode* pHead);来完成,代码如下。

void ListPopBack(ListNode* pHead)
{assert(pHead);ListNode* p = pHead->_prev;p->_prev->_next = pHead;pHead->_prev = p->_prev;free(p);
}

带头双向循环链表的头删和尾删都比较简单,关键点还是在于找准哨兵位头节点的头尾指针。接下来就是链表的随机删的实现,随机删除我们用函数ListErase(ListNode* pos);来完成,如下代码。

void ListErase(ListNode* pos)
{assert(pos);if (pos == pos->_next){return;}pos->_prev->_next = pos->_next;pos->_next->_prev = pos->_prev;free(pos);
}

😂链表搜索和链表修改

在完成了链表的增加和删除后,剩下的就是链表的搜索和修改,链表的搜索我们用函数ListFind(ListNode* pHead, LTDataType x);来完成,如下代码。

ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* p = pHead->_next;while (p != pHead){if (p->_data == x){return p;}p = p->_next;}return NULL;
}

链表的修改我们用函数ListModify(ListNode* pHead, LTDataType x)来完成,如下代码。

ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* p = pHead->_next;while (p != pHead){if (p->_data == x){return p;}p = p->_next;}return NULL;
}
void ListModify(ListNode* pHead, LTDataType x)
{ListNode* p = ListFind(pHead, x);scanf("%d", &p->_data);
}

💡总结

到此为止,带头双向循环链表的增删改查就全完成了,带头双向循环链表是链表中使用起来最方便,功能最全的链表,因此我们合理的应用带头双向循环链表可以帮助我们事半功倍,解决不少问题。另外题外话,刚刚🐏康归来,好久都没写博客了,被这个疫情搞得一团糟,中招了是真难受啊,小伙伴们自己注意防护吧。

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...