📅  最后修改于: 2023-12-03 15:07:22.946000             🧑  作者: Mango
双链表是一种数据结构,它可以在任意位置插入/删除元素,并且可以双向遍历。相较于单链表,双链表需要记录前后两个链表节点,因此需要更多的内存空间。但是在某些情况下,使用双链表可以更加高效地解决问题。
双链表由节点组成,每一个节点包含三个部分:前驱指针、后继指针和数据部分。其中,前驱指针指向前一个节点,后继指针指向下一个节点,数据部分存储节点所代表的数据。
template <typename T>
struct ListNode {
T val;
ListNode* prev;
ListNode* next;
ListNode(T x) : val(x), prev(nullptr), next(nullptr) {}
};
双链表可以在任意位置插入节点,具体过程如下:
template <typename T>
void insert(ListNode<T>*& head, ListNode<T>* node, T val) {
ListNode<T>* new_node = new ListNode<T>(val);
new_node->prev = node;
new_node->next = node->next;
node->next = new_node;
if (new_node->next != nullptr) {
new_node->next->prev = new_node;
}
}
删除节点需要先找到要删除的节点,具体过程如下:
template <typename T>
void remove(ListNode<T>*& head, ListNode<T>* node) {
if (node == nullptr) {
return;
}
if (node->prev != nullptr) {
node->prev->next = node->next;
} else {
head = node->next;
}
if (node->next != nullptr) {
node->next->prev = node->prev;
}
delete node;
}
双链表可以双向遍历,具体过程如下:
template <typename T>
void traverse(ListNode<T>* head) {
printf("from head to tail: ");
for (ListNode<T>* p = head; p != nullptr; p = p->next) {
printf("%d ", p->val);
}
printf("\n");
printf("from tail to head: ");
for (ListNode<T>* p = get_tail(head); p != nullptr; p = p->prev) {
printf("%d ", p->val);
}
printf("\n");
}
双链表可以优化一些需要大量随机插入和删除的场景,比如 LRU Cache 的实现。
双链表是一种比较常用的数据结构,使用它可以高效地解决某些问题。对于程序员来说,学习双链表是必不可少的。