题目:给定单链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点
分析:
1.在寻常的单链表中删除一个节点,使用的最多的做法就是从链表的头结点开始,遍历链表,找到要删除的节点,并在链表中删除该节点,比如我要删除链表中节点b,我在遍历的时候找到了b节点的上一节点a,那么我可以把a节点的指针指向b节点的下一节点,这样就完成了对b节点的删除。但是需求规定的是我们完成删除操作时,时间复杂度为O(1),上述的做法的时间复杂度为O(n)
2.我在翻数据结构的参考书时,我发现在链表中删除一个特定节点并不一定要找到删除节点的上一节点才能完成删除操作,还有一种做法是:如果要被删除的节点的下一节点不为空,可以把该节点的value复制给要被删除的节点,同时删除要被删除节点的下一节点,这样,要被删除的节点就被完全删除了(仔细理解我这几句话,这样操作等于把它的下一节点完全覆盖了要被删除的节点,同时把它的下一节点取出)。
那么,在以上的基础上,有人会问,如果要删除的节点位于链表的尾部(也就是说要被删除的节点的下一节点为空)怎么办?我们此时可以从链表的头结点开始,遍历得到该节点的前序节点,并完成删除操作。
最后,还有一点需要注意,如果链表中只有一个节点,即这个节点既是头结点也是尾节点,那么我们在删除该节点后还要把该链表的头结点设置为null。
具体实现代码如下:
class ListNode{
int value;
ListNode next;
public ListNode(){
}
public ListNode(int value){
this.value =value;
}
public ListNode(int value,ListNode next){
this.next =next;
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
public static void deleteNode(ListNode head,ListNode tobeDeleted){
if(head == null || tobeDeleted ==null){
return;
}
/**
* 如果要被删除的节点的下一节点不是尾节点,则把被删除节点下一节点的value复制给要被删除的节点,同时删除被删除节点的下一节点,这样就完成了
* 删除节点的操作
*/
if (tobeDeleted.getNext() != null){
ListNode p = tobeDeleted.getNext();//p为被删除节点的下一节点
//把p的value复制给被删除的节点
tobeDeleted.setValue(p.getValue());
//删除p节点
tobeDeleted.setNext(p.getNext());
}else if(head == tobeDeleted){//如果头结点就是要被删除的节点,则直接删除头结点
head =null;
}else{
//此时该节点恰好为链表的尾节点,则从头结点开始,遍历得到该节点的前序节点,再删除该节点
ListNode currentNode = head;
while (currentNode.getNext() != tobeDeleted){
currentNode = currentNode.getNext();
}
currentNode.setNext(null);
}
}
时间复杂度分析:除了要删除的节点为尾节点的情况,我们在n-1个节点中删除操作,都可以在O(1)时把下一个节点的内容覆盖该节点(在代码中体现),但是如果要删除的的节点恰好是尾节点,那么时间复杂度为O(n),但是两种情况下平均下来还是O(1),这符合了题目的要求