链表中删除指定结点的两种方式

题目:给定单项链表的头指针和一个结点指针,定义一个函数在o(1)的时间删除该结点,链表的定义如下:

struct ListNode{
  int value;

  ListNode* next;

};

函数定义:void DeleteNode(ListNode** PListHead,ListNode* pToBedelete);

 

如上图所示,想要删除一个单链表的中的某个结点有两种方式:

1、如上图中的( b)所示:要删除i结点,必须从头扫描,扫到h(i的前一个结点),然后让其next值指向j(i的下一个位置),然后就可以删除i了。此方法的复杂度为O(n),因为要删除某个结点必须找到其上一个结点,故需要从头遍历。

2、如上图中的(c)所示:要删除i结点,可以先把i的下一节点的值赋给i结点,然后让i的next值指向下一节点的下一结点,就相当于删除i结点。(注意要保存i->next的这个结点,然后再删除),此算法复杂度为O(1),但是必须要求此要删除结点一定是链表中的结点,且当要删除的结点为最后一个结点时,必须用第一种方法,顺序遍历后找到最后一结点的上一结点,然后删除,但此方法的平均时间复杂度仍然为O(1).

3、如果链表中只有一个结点,而我们又要删除链表的头结点,那么我们在删除节点之后,需要把结点置为空

4、我们以上所有的操作都是基于一个假设,要删除的节点就在链表中。


删除链表指定节点的操作可以通过遍历链表并修改指针来完成。下面分别对**单向链表**、**双向链表**以及**循环链表**这三种链表结构进行简要说明,并提供相应的思路。 --- ### **1. 单向链表** 对于单向链表,每个节点只包含一个指向下一个节点的引用(`next`)。如果需要删除某个特定节点,则需找到目标节点前驱节点并将该节点链表中断开连接。 #### 实现步骤: - 初始化临时变量 `prev` 和 `curr` 分别表示当前节点及其前驱。 - 遍历整个列表直到遇到空节点为止。 - 如果发现某节点的数据域等于待删数据,则将 `prev.next = curr.next` 来跳过此节点。 ```python class ListNode: def __init__(self, x): self.val = x self.next = None def removeElements(head: ListNode, val: int) -> ListNode: dummy = ListNode(0) dummy.next = head prev, curr = dummy, head while curr: if curr.val == val: prev.next = curr.next # 跳过当前节点 else: prev = curr # 移动到下一节点 curr = curr.next # 更新游标 return dummy.next ``` --- ### **2. 双向链表** 相比单向链表,在双端链表里除了有 `next` 指向外还有另一个字段叫做 `prev` 表示回溯上一节点的关系。因此在移除元素时不仅要改变前方链接也要同步调整反方向关系以防断裂。 #### 步骤描述: 1. 定义辅助函数用于定位含有目标数的第一项实例; 2. 确定它存在之后检查是否处于首末端位置特别处理边界情况; 3. 修改前后两邻居间的联系即设置新近邻为彼此直接关联而略去中间环节。 ```java public class DoublyLinkedList { public Node head; static class Node { int data; Node next, prev; public Node(int d){ this.data=d; this.prev=null;this.next=null; } } void deleteNode(Node del) { // 若头结点就是应该被删除的那个就特殊对待一下吧~ if (head==del){ head=head.next ; if(head!=null ){ head.prev=null ;} }else{ del.prev .next=del.next ; if(del.next != null ){ del.next .prev=del.prev;} } } } ``` --- ### **3. 循环链表** 这种类型的链条其特征在于最后一个实体并非终止于NULL而是回到最前端构成闭环形式。针对这类布局下执行剔除操作依旧沿用之前方法论仅需额外考虑收尾交接处特殊情况即可顺利完成任务。 #### 思路分析: - 因为它是圆圈所以当走到尽头又会绕回来开始的地方。我们得注意这个特性,避免陷入无限递归陷阱之中。 - 当然这里也有一个小技巧可以先判断是否有符合要求的东西再做进一步动作防止不必要的浪费运算资源哦~ 伪代码参考如下所示: ```c++ struct node *remove_from_circular_list(struct node* list, struct node* to_remove){ if(list == NULL || to_remove == NULL) return list; if(to_remove->next != NULL && to_remove->prev != NULL){ to_remove->prev->next = to_remove->next; to_remove->next->prev = to_remove->prev; if(list == to_remove){ list = to_remove->next; } free(to_remove); } return list; } ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值