一. 结构图和哨兵位
我们先来看它的结构图
这里的结构大体如上
我们可以发现的是 这里其实是有一个哨兵位
那么什么是哨兵位呢?
之前的一期我们讲过,可以看我的往期文章
二. 代码实现
我们还是跟以前一样 先创建三个工程文件
创建一个节点所需要的指针和值
typedef int LTDateType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
LTDateType date;
}LTNode;
这样子如果我们想要改变双链表存储的值的话只需要改变typedef的类型就可以了
三. 初始化双链表
这里很简单 我们只需要创建一个哨兵位就可以
这个哨兵位的头尾指针都要指向自身
代码表示如下
LTNode* BuyListNode(LTDateType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc fail");
//return NULL;
exit(-1);
}
node->next = NULL;
node->prev = NULL;
node->date = x;
return node;
}
LTNode* LTInit()
{
LTNode* phead = BuyListNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
四. 尾插数据
我们来看图
首先我们需要通过tail找到一个尾
之后通过这个尾来向后插入一个新的数据
一共有四个箭头需要链接(尾2 新节点2)
之后我们开始找尾 插入数据
代码表示如下
void LTPushBack(LTNode* phead, LTDateType x)
{
assert(phead);
LTNode* newnode = BuyListNode(x);
LTNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
/*LTInsert(phead, x);*/
}
五. 打印数据
没有什么难度
代码表示如下
void LTPrint(LTNode* phead)
{
assert(phead);
printf("<=head=>");
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d<=>", cur->date);
cur = cur->next;
}
printf("\n");
}
接下来我们试试看打印尾插的数据
我们发现没有问题
六. 尾删数据
首先我们需要找到tail之前的一个数据 我们将这个数据称之为prev
然后按照上图链接就可以
但是又一种特殊情况 如果说 head 既是头又是尾 我们这里就需要报错
因为哨兵位不可以删除
代码表示如下
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
tailPrev->next = phead;
phead->prev = tailPrev;
free(tail);
tail = NULL;
}
然后效果表示如下
七. 头插数据
还是一样 我们先看图
代码表示如下
void LTPustFront(LTNode* phead, LTDateType x)
{
assert(phead);
LTNode* newnode = BuyListNode(x);
LTNode* first = phead->next;
phead->next = newnode;
newnode->prev = phead;
newnode->next = first;
first->prev = newnode;
//不能随便换顺序
//newnode->next = phead->next;
//phead->next->prev = newnode;
//
//phead->next = newnode;
//newnode->prev = phead;
/*LTInsert(phead->next, x);*/
}
显示效果如下
八. 头删数据
我们发现要头删除数据的话要使用三个指针
哨兵位指针
头指针
头指针的下一位
开始写代码
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* first = phead->next;
phead->next = first->next;
first->next->prev = phead;
free(first);
first = NULL;
}
显示效果如下
九. 查找指定位置
这个实现起来也很简单 跟打印的思路差不多
LTFind(LTNode* phead, LTDateType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur!=phead)
{
if (cur->date == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
如果找到return pos的位置
如果找不到我们就返回一个空指针
十. 指定位置前插入数
如图
看图敲代码
void LTInsert(LTNode* pos, LTDateType x)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* newnode = BuyListNode(x);
newnode->next = pos;
pos->prev = newnode;
prev->next = newnode;
newnode->prev = prev;
}
我们来看看效果
十一. 删除指定位置的数
还是一样 先看图
这里我们需要三个指针 一个前面的一个后面的
但是这里我们需要注意
Pos指针不能为空
并且Pos指针不能指向头节点
我们来看看代码
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* next = pos->next;
prev->next = next;
next->prev = prev;
free(pos);
pos = NULL;
}
我们再看看效果图怎么样
以上便是本文所有内容了,如有错误请各位大佬不吝赐教,感谢留言