使用递归删除链表


链表

链表是一种线性数据结构,其元素存储在非连续的内存位置。每个元素包含一个节点。一个节点由一个数据字段组成,该字段保存元素的值,以及一个地址字段,该字段指向系列中下一个节点的位置。

链表的第一个节点称为列表的“头”。链表的最后一个元素可以定义为指向NULL的元素。下面显示了链表的图表表示。

问题陈述

给定一个链表,任务是使用递归删除所有元素,即链表的头应为NULL。

解决方案方法

要删除链表的所有元素,我们遍历链表并逐个删除所有节点。当头等于NULL时,链表被认为为空。

算法

该方法包括以下步骤:

  • 如果头等于NULL,则返回

  • 递归删除头节点指向的节点。

  • 删除头节点。

  • 显示答案。

伪代码

类节点()

  • 定义公共变量“data”

  • 定义公共变量“next”

  • 构造函数节点(val)

    • 初始化data = val

    • 初始化next = NULL

函数insert(key)

  • 使用数据值“key”初始化新节点“n”。

  • 如果(head == NULL)

    • 设置head = n

    • 返回

  • 初始化temp = head

  • 当(temp->next != NULL)

    • temp = temp->next

  • 设置temp->next = n

  • 返回

函数deleteLL()

  • 如果(head == NULL)

    • 返回

  • 函数调用deleteLL(head->next)

  • free(head)

函数printLL()

  • 初始化temp = head

  • 当(temp != NULL)

    • 打印temp->data

    • temp = temp->next

  • 返回

干运行

Input: 1 -> 2 -> 3 -> 4
Output: [ ]

说明 - 在将所有节点一个接一个地插入到链表中之后,链表可以表示为

当使用此列表的头(即节点1)调用deleteLL()函数时,它首先检查head是否为NULL。由于它不是,它会使用列表中的下一个节点(即节点2)调用自身。

对deleteLL()的第二次调用检查当前头(即节点2)是否为NULL。由于它不是,它会使用列表中的下一个节点(即节点3)调用自身。

类似地,它会使用节点4调用自身。在此之后,在下一个调用中,head = NULL,因为我们已经到达链表的末尾。因此,函数返回到链表中的先前调用并释放当前头节点。

简单来说,节点的删除顺序相反:4 -> 3 -> 2 -> 1。

示例:C++程序

下面的C++程序使用insert()函数逐个将一系列节点插入到链表中。然后,它使用函数printLL()打印原始列表。之后,它通过递归调用函数deleteLL()删除列表的所有节点。它以相反的顺序删除节点。然后它将head赋值为NULL。最后,它使用函数printLL()打印空链表。

下面的C++程序递归地删除给定的链表:

#include <bits/stdc++.h>
using namespace std;
// A linked list node class. Each node consists of a data field and an address field.
class node {
public:
   int data;
   node *next;
   
   node(int val){
      data = val;
      next = NULL;
   }
};

// This function inserts a node to form a linked list.
// We push a new node to the end of the list if the head of the linked list is given.
void insert(node *&head, int key){
   node *n = new node(key);
   if (head == NULL){
      head = n;
      return;
   }
   node *temp = head;
   while (temp->next != NULL){
      temp = temp->next;
   }
   temp->next = n;
   return;
}

// This function recursively deletes all the nodes of the linked list one by one.
void deleteLL(node *&head) {
   if (head == NULL){
      return;
   }
   deleteLL(head->next);
   free(head);
}

// This function prints all the nodes of the linked list.
void printLL(node *head) {
   node* temp = head;
   while (temp != NULL){
      cout << temp->data << " ";
      temp = temp->next;
   }
}

// Driver function
int main(){
   node *head = NULL;
   insert(head, 1);
   insert(head, 2);
   insert(head, 30);
   insert(head, 4);
   insert(head, 5);
   insert(head, 60);
   cout << "Original Linked List: ";
      printLL(head); // 1 2 30 4 5 60
   cout << "Linked List after Deletion: ";
      deleteLL(head);
   
   // after we free(head), it now points to an illegal location
   // so we set head equal to NULL
   head = NULL;
   printLL(head); // empty linked list
   return 0;
}

输出

Original Linked List: 1 2 30 4 5 60 Linked List after Deletion:

时间和空间复杂度分析

时间复杂度:O(n)

  • insert()函数的时间复杂度为O(n),因为它遍历链表以找到末尾。

  • printLL()函数的时间复杂度为O(n),因为它也遍历整个链表。

  • 递归删除链表的deleteLL()函数的时间复杂度为O(n),因为它访问每个节点一次。

空间复杂度:O(n)

  • insert()函数的空间复杂度为O(1),因为它不需要任何额外空间。

  • 此外,printLL函数也不使用额外的空间,因此其空间复杂度为O(1)。

  • deleteLL()函数是一个递归函数,它使用调用栈来跟踪要删除的节点。调用栈的最大深度将等于链表中的节点数。因此,deleteLL函数的空间复杂度为O(n)。

因此,代码的整体空间复杂度为O(n)。

结论

链表可以用来实现像栈、队列和哈希表这样的数据结构。它们是有用的数据结构,可以被认为是动态数组。本文讨论了删除链表的递归方法。它详细解释了链表的概念、递归解决方案的方法以及C++程序代码、干运行和时间和空间复杂度分析。

更新于:2023年4月19日

966 次浏览

启动您的职业生涯

通过完成课程获得认证

开始学习
广告