数据结构:双向链表实现与算法实战
上一节我们梳理了双向链表的概念与基础结构,本节将深入其核心操作的具体实现,包括查找、插入、删除的指针调整细节,并对比顺序表与链表的差异,最后通过两道经典算法题巩固理解。
一、双向链表核心操作实现
1. 查找节点
查找逻辑与单链表类似,利用临时指针遍历即可。由于是循环双向链表,终止条件为回到头结点。
ListNode* LTFind(ListNode* h, type x) {
if (LTEmpty(h)) return NULL;
ListNode* p = h->next;
while (p != h) {
if (p->data == x) return p;
p = p->next;
}
return NULL;
}
2. 指定位置插入
双向链表在指定位置插入分为'之后'和'之前'两种情况,关键在于维护 prev 和 next 的双向连接。
在指定节点后插入
核心是四步指针调整:先保存后继,再断连,最后建立新节点与前驱、后继的关系。
void LTInsert(ListNode* pos, type x) {
assert(pos);
ListNode* p = pos->next; // 保存原后继
ListNode* newnode = LTcreat(x); // 创建新节点
pos->next = newnode; // 前驱指向新节点
newnode->prev = pos; // 新节点指向前驱
newnode->next = p; // 新节点指向后继
p->prev = newnode; // 后继指回新节点
}
在指定节点前插入
需先找到目标节点的前驱,逻辑与上述类似,只是基准点不同。
void LTInsertfront(ListNode* h, ListNode* pos, type x) {
if (LTEmpty(h)) return;
ListNode* p = h;
// 寻找 pos 的前驱
(p->next != h && p->next != pos) {
p = p->next;
}
(p->next == h) ;
ListNode* newnode = (x);
ListNode* pr = p->next;
newnode->next = pr;
newnode->prev = p;
p->next = newnode;
pr->prev = newnode;
}


