双链表就是带头-循环-双向的链表,下面我们来实现一下双链表
双链表的初始化
双链表由数据(data)、指向下一节点的指针(next)、指向上一节点的指针(prev)组成
cpp
LTNode* LTBuyNode(LTDataType x)
{
LTNode* tmp = (LTNode*)malloc(sizeof(LTNode));
if (tmp == NULL)
{
perror("LTBuyNode");
exit(1);
}
//空双向链表表示哨兵位两个指针指向他自己
// 不代表指针为空指针
//因为双向链表是循环的,所以头结点的两个指针均指向他自己
tmp->data = x;
tmp->next = tmp;
tmp->prev = tmp;
return tmp;
}
void LTInit(LTNode** pphead)
{
*pphead = LTBuyNode(-1);
}
双链表中插入数据
在双链表的尾部插入数据
cpp
//哨兵位的节点不能被删除也不能被修改,所以传一级指针即可
//先修改新节点的两个指针,在修改哨兵位的指针
void LTPushBack(LTNode* phead, LTDataType x)
{
//将新节点插入到头节点前面
LTNode* tmp = LTBuyNode(x);
tmp->next = phead;
tmp->prev = phead->prev ;
//先修改尾节点指向新节点,再修改尾节点为新节点
phead->prev->next = tmp;
phead->prev = tmp;
}
在双链表的头部插入数据
cpp
void LTPushFront(LTNode* phead, LTDataType x)
{
//将新节点插入到第一个有效节点的前面就是头插
//还是先修改新节点的两个指针
LTNode* newNode = LTBuyNode(x);
newNode->prev = phead;
newNode->next = phead->next;
phead->next->prev = newNode;
phead->next = newNode;
}
在双链表指定位置之后插入数据
cpp
void LTInsert(LTNode* pos, LTDataType x)
{
//在指定位置之后插入节点
//依旧是先修改新节点的指针
assert(pos);
LTNode* newNode = LTBuyNode(x);
newNode->prev = pos;
newNode->next = pos->next;
pos->next->prev = newNode;
pos->next = newNode;
}
双链表删除数据
删除双链表尾部的数据
cpp
void LTPopBack(LTNode* phead)
{
//将倒数第二个节点的下一个节点改成头节点
//将头结点的上一个节点改成倒数第二个节点
assert(phead);
LTNode* tmp = phead->prev;
tmp->prev->next = phead;
phead->prev = tmp->prev;
free(tmp);
tmp = NULL;
}
删除双链表头部的数据
cpp
void LTPopFront(LTNode* phead)
{
assert(phead);
LTNode* tmp = phead->next;
phead->next = tmp->next;
tmp->next->prev = phead;
free(tmp);
tmp = NULL;
}
删除双链表指定位置的数据
cpp
void LTErase(LTNode* pos)
{
assert(pos);
//pos不能是哨兵位
//这里虽然对pos指针进行了修改,但是为了保证
//函数接口的一致性,所以传一级指针。
//但是这样并不会对实参置空,所以要在主函数中对实参置空
pos->next->prev = pos->prev;
pos->prev->next = pos->next;
free(pos);
pos = NULL;
}
查找双链表中的数据
cpp
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
双链表的销毁
cpp
void LTDestroy(LTNode* phead)
{
//这里同样为了函数接口一致性,传递一级指针
//在主函数中需要释放掉实参的内存
assert(phead);
LTNode* pcur = phead->next;
LTNode* prev = phead->next;
while (prev != phead)
{
pcur = pcur->next;
free(prev);
prev = pcur;
}
free(phead);
phead = NULL;
}