📜  删除双向链表中所有出现的给定键(1)

📅  最后修改于: 2023-12-03 15:22:42.917000             🧑  作者: Mango

删除双向链表中所有出现的给定键

双向链表是一种经常用于实现LRU Cache(最近最少使用缓存)等数据结构的基础数据结构。在实际开发中,在某些情况下,我们需要删除双向链表中所有出现的给定键,这里为大家介绍如何实现。

前置知识

在阅读本文之前,建议程序员需要掌握的知识点包括:

  • 双向链表的基本操作,如头插、尾插、遍历等;
  • 链表节点的结构体定义;
  • C/C++语言基础。

如果您还不熟悉双向链表或链表节点的定义,可以先阅读以下文章:

思路分析

要删除双向链表中所有出现的给定键,我们可以遍历整个链表,每当遇到给定键的节点就将其删除,直到遍历完整个链表。需要注意的是,由于有些节点被删除之后,链表的头指针也可能发生变化,因此我们需要在遍历的过程中维护头指针的正确性。

具体来说,我们可以采用以下的算法:

  1. 初始化一个指针p指向链表的头节点head,一个指针prev指向p的前一个节点;
  2. 在一个while循环中,遍历整个链表,每当遇到给定键k时,将p指针所指的节点删除,prev指向p的下一个节点,p指向原来p的下一个节点;
  3. 接着在while循环中,如果p指针所指的节点不是给定键k,那么将prev指针指向p,p指针指向p的下一个节点;
  4. 重复2-3步骤,直到整个链表被遍历完。
代码实现

基于以上的思路分析,我们可以编写如下C++代码实现双向链表中所有出现给定键的删除操作:

struct ListNode {
    int val;
    ListNode* prev;
    ListNode* next;
    ListNode(int x) : val(x), prev(NULL), next(NULL) {}
};

class Solution {
public:
    ListNode* deleteNode(ListNode* head, int key) {
        ListNode *p = head;
        ListNode *prev = NULL;
        while (p != NULL) {
            if (p->val == key) {
                if (prev == NULL) {
                    head = p->next; // 如果要删除的节点是头节点,更新头指针
                    if (head != NULL) {
                        head->prev = NULL;
                    }
                } else {
                    prev->next = p->next;
                    if (p->next != NULL) {
                        p->next->prev = prev; // 如果要删除的节点是中间节点,更新前后指针
                    }
                }
                ListNode *q = p;
                p = p->next;
                free(q);
            } else {
                prev = p;
                p = p->next;
            }
        }
        return head;
    }
};

以上代码定义了一个双向链表节点的结构体ListNode,里面有val(节点的值)、prev(指向前一个节点的指针)、next(指向后一个节点的指针)三个字段。同时,这里我们用面向对象的思想定义了一个Solution类,其中的deleteNode函数实现了我们的思路分析。

具体来说,deleteNode函数的输入参数head是要删除节点的双向链表的头指针,key是要删除的节点的值。它的返回值是删除后的双向链表的头指针。

在deleteNode函数中,我们用一个while循环遍历整个链表,每当遇到要删除的节点时,就将其删除。如果要删除的节点是头节点,那么我们需要更新头指针head的值;如果要删除的节点是中间节点,那么我们需要更新前后指针的值。最后,我们还需要释放被删除的节点的内存空间,然后将指针p指向被删除节点的下一个节点。

在出现key相等的节点时,我们需要删除该节点,同时维护prev和p指针的值。如果p指针指向的节点不是要删除的节点,那么我们只需要将prev指针指向p,将p指针指向p的下一个节点即可,由于该节点不需要删除,我们无需释放其内存空间。

性能分析

假设链表的长度为n,我们需要遍历整个链表,时间复杂度为O(n)。在每次遇到给定键时,我们需要删除一个节点,因此需要进行常数次的内存读写操作,时间复杂度为常数级别。因此,总时间复杂度为O(n)。

由于双向链表中可以通过指针快速定位前后节点,因此其删除操作的空间复杂度通常为O(1)。但在本算法实现中,由于采用了free函数释放节点空间,因此空间复杂度看起来是O(n)的。不过由于空间复杂度与双向链表的实现方法和具体算法实现相关,因此在不同场景下可能会发生变化。

总结

本文介绍了如何删除双向链表中所有出现的给定键。我们从思路分析、代码实现和性能分析三方面对该算法进行了介绍和分析。双向链表作为常用的基础数据结构,其删除节点的操作是十分重要的,希望读者通过本文的学习能掌握该算法并在实际开发中得到应用。