题目如下:
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
首先,定义一个内部类表示结点:
class Node{
public Node(int n){
this.number = n;
}
public Node(){
this(0);
}
private int number;
private Node next;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node [number=" + number + "]";
}
}
删除一个节点,最直观的方法就是,从头节点开始,依次遍历查询是否有节点和这个节点相同,找打之后,令这个节点的前一个节点的next指针指向删除节点的下一个节点。再将要删除的节点删除即可。这种想法可以用如下代码实现:
private static Node deleteListNode(Node root , Node delelte) {
// TODO Auto-generated method stub
if (root == null) {
throw new RuntimeException();
}
if (root.getNumber() == delelte.getNumber()) {
//要删的节点是首节点
return root.getNext();
}
Node tmp = root;
//备份头结点
boolean flag = false;
while(root.getNext() != null){
if (root.getNext().getNumber() == delelte.getNumber()) {
//此时root是待删节点的前一个节点
flag = true;
if (root.getNext().getNext() == null) {
//处理删除最后一个节点的情况
root.setNext(null);
return tmp;
}
break;
}else{
root = root.getNext();
}
}
if (flag) {
root.setNext(root.getNext().getNext());
}
return tmp;
}
但这种方法的时间复杂度是O(n),并不符合题目中的要求,因此我们采用如下的方法。
我们并不需要知道删除节点的前一个节点然后取改变他的next指针,我们可以直接覆盖掉要删除的节点,即直接将删除节点的数值域改为其下一个节点的数值,再将删除节点的next指针直接指向其下一个节点的下一个节点即可。但这种方法,要考虑特殊的情况,比如,若我们要删除的节点是首节点,我们则直接返回他的下一个节点(若只有一个节点我们就返回空(null))。若我们删除的是最后一个节点,这里注意并不能直接令其等于空(null)。因为java是值传递,我们在方法之间传递的删除节点只是复制了他的地址并不是直接传递了他的引用,因此我们不能直接把改变其指向。因此只能采用上面那种方法去逐个查找。实现代码如下:
private static Node deleteListNodeInO1(Node root , Node delete) {
// TODO Auto-generated method stub
if (root == null) {
throw new RuntimeException();
}
if (root.getNumber() == delete.getNumber()) {
//要删的节点是首节点
return root.getNext();
}
Node tmp = root;
//备份头结点
if (delete.getNext() == null) {
//删除的是尾节点
//注意:不能直接写delete= null,java是值传递
return deleteListNode(root , delete);
}
delete.setNumber(delete.getNext().getNumber());
//设置节点数字为下个节点的数字
delete.setNext(delete.getNext().getNext());
//设置节点next指针,为其指向的节点的next指针
return tmp;
}