目录
1. 什么是双向链表
双向链表特点:
1.每次在插入或删除某个节点时, 需要处理四个节点的引用, 而不是两个. 实现起来要困难一些
2.相对于单向链表, 必然占用内存空间更大一些.
3.既可以从头遍历到尾, 又可以从尾遍历到头
双向链表的定义:
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。下图为双向链表的结构图。
2. 双向链表的实现
1.双向链表的结构共有三部分组成:一个数据域和两个指针域
指针域:用于指向当前节点的直接前驱节点;
数据域:用于存储数据元素。
指针域:用于指向当前节点的直接后继节点;
它的结点结构用c语言:
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* prev;
struct ListNode* next;
LTDataType data;
}LTNode;
3. 双向链表的初始化
初始化这里用了两步:创建BuyLTNode函数,然后创建哨兵位,将哨兵位的prev指针和next指针指向本身就是初始化操作。
LTNode* BuyLTNode(LTDataType x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = newnode->prev = NULL;
return newnode;
}
LTNode* LTInit()
{
LTNode* phead = BuyLTNode(-1);//给哨兵位赋值-1在这里没有任何意义
phead->next = phead->prev = phead;
return phead;
}
4. 双向链表的插入
4.1 头插
这里的头插操作非常简单,记录head结点之后的第一个结点为first,然后创建新结点newnode将需要插入的新结点与head和first利用它们的prev和next相互连接。
图解:
代码如下:
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* first = phead->next;
LTNode* newnode = BuyLTNode(x);
newnode->next = first;
newnode->prev = phead;
phead->next = newnode;
first->prev = newnode;
}
4.2 尾插
尾插与头插类似,但记录的结点为最后一个也就是head->prev,将最后一个结点记录为last,创建新结点newnode,newnode与last和head通过prev指针和next指针相互连接。
代码如下:
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode*last = phead->prev;
LTNode* newnode = BuyLTNode(x);
last->next = newnode;
newnode->next = phead;
phead->prev = newnode;
newnode->prev = last;
}
4.3 在pos之前插入(在任意位置插入)
首先创建LTFind函数,寻找链表中想要位置的元素,利用LTFind函数找到需要的元素再赋值给pos。
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data != x)
{
cur = cur->next;
}
else
{
return cur;
}
}
return NULL;
}
再创建newnode插入到pos之前位置,即可完成想插哪里就插哪里。
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = BuyLTNode(x);
LTNode* cur = pos->prev;
cur->next = newnode;
newnode->prev = cur;
newnode->next = pos;
pos->prev = newnode;
}
5.双向链表的删除
运用LTFind函数找到需要的pos位置然后再利用LTErase函数删除pos位置。
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data != x)
{
cur = cur->next;
}
else
{
return cur;
}
}
return NULL;
}
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* qian = pos->prev;
LTNode* hou = pos->next;
qian->next = hou;
hou->prev = qian;
free(pos);
}
这些就是关于双向链表的知识,如果感觉up主写的不错,麻烦友友们点个赞支持一波。