一个结构体包含两个指针:一个是前驱,另一个是后驱
看似复杂代码写起来是罕见单的,所以……
上代码熟悉!!!!源码放在下面了,很简单供复习所用
//结构体写出来
typedef struct List
{
int data;
struct List* prev; //前后指针
struct List* Next;
}ListNode;
不管你是顺序表还是单链表或者循环链表还是队列栈都要包含这些头文件
#include<stdio.h>
#include<stdlib.h> //一般是free要用到
#include<assert.h> //断言
#include<stdbool.h> //bool
写一个简单的接口那一定是新建节点和初始化两者简单也最基础:
#include“List.h” //函数接口在.c文件中要引用
//增加节点函数
SL*Add(int x)
{
ListNode*newnode=(ListNode*)malloc(sizeof(SL)); //不多解释懂得都懂
newnode->prev=NULL;
newnode->Next=NULL;
newenode->data=x
return newnode;
}
//初始化函数
SL* SqlInit()
{
ListNode*phead=Add(0);
phead->prev=phead; //为什么会指向自己呢?有什么好处?? 简单想一下是不是会形成闭环
phead->Next=phead;
return phead;
}
上面的代码虽然没有亮这个颜色,但并不代表他不对只不过有些东西没法引入
初始化为何要进行返回值呢??顺序表不用返回呀。这是为何呢??这是与主代码中的操作有关,在这里我就不写了,直接吧visual studio2022的代码拿过来了
上图是顺序表的图 他要把顺序表初始化才好增删查改
上图的表是循环链表的图,因为调用者需要知道链表的起始位置,以便后续操作(如添加、删除、遍历节点等
上面的只是小菜,循环链表的核心是增删查改。简单写一个尾插接口,并且简单分析一下。
//尾插
void ListPushBack(ListNode*phead,int x)
{
assert(phead); //断言防止phead为空指针,当然在上面已经初始化了不存在空
ListNode*tail=phead->prev;
ListNode*newnode=BuyListNode(x);
newnode->Next=phead;
newnode->prev=tail;
tail->Next=newmode;
phead->prev=newnode;
}
用图来解释可能更好
如果没有数据,尾插可不可以呢?答案是可以的因为在初始化中phead->Next = phead;
phead->prev= phead; 这段代码的精妙之处在尾插就凸显出来了。
尾插写完头插也是一样的思路我就直接上图了
其实可以用一种随机插入来替代尾插头插
//在随机插入之前需要找到位置所以要写一个查找函数
ListNode* ListFind(ListNode* phead, LTDateType x)
{
assert(phead);
ListNode* cur=phead->Next;
while(cur!=phead)
{
if(cur->data==x)
{
return cur;
}
cur=cur->Next;
}
return NULL;
}
//接下来就是随机插入接口了
ListNode* ListIsert(ListNode*pos,LTDateType x)
{
assert(pos);
ListNode* prev = pos->prev;
ListNode* newnote = BuyListNode(x);
prev->Next = newnote;
newnote->Next = pos;
newnote->prev = prev;
pos->prev = newnote;
}
销毁函数如下:
void ListDestory(ListNode* phead)
{
ListNode* cur = phead->Next;
while (cur != phead)
{
ListNode* Next = phead->Next;//继续销毁
free(cur);
cur = Next;
}
free(phead);
phead = NULL;
}
以上就是基本的接口。看似简单实则比顺序表、单链表都简单。用两个指针解决了棘手问题。
那么在实际应用开发中双向循环链表用什么应用吗?不防让kimi来回答一下:
在让chatgpt来回答一下:
两者差不多少,其实不管是双向的还是单向的对数据的索引几乎没有差别。无非循环的是循环而已,在实际应用开发几乎没有差别。在一些细微方面有所区别:比如线程安全并发控制上。单链表在插入或删除头部节点时性能较好。其实差别微小到看不见。