本文參考自《劍指offer》一書,代碼採用Java語言。html
更多:《劍指Offer》Java實現合集 java
給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該結點。node
一般那樣從頭開始查找刪除須要的時間爲O(n),要在O(1)時間刪除某結點,能夠這樣實現:設待刪除結點i的下一個結點爲j,把j的值複製到i,再把i的指針指向j的下一個結點,最後刪除j,效果就至關於刪除j。面試
注意特殊狀況:1.當待刪除結點i爲尾結點時,無下一個結點,則只能從頭至尾順序遍歷;2.當鏈表中只有一個結點時(便是頭結點,又是尾結點),必須把頭結點也設置爲null。ide
本題有個缺陷:要求O(1)時間刪除,至關於隱藏了一個假設:待刪除的結點的確在表中函數
測試算例post
1.功能測試(多個結點鏈表,刪除頭結點、中間結點和尾結點;單個結點鏈表)測試
2.特殊測試(頭結點或刪除結點爲null)url
(含測試代碼)spa
package _18; /** * * @Description 面試題18(一):在O(1)時間刪除鏈表結點 * * @author yongh * @date 2018年9月18日 下午3:57:59 */ //題目:給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該 //結點。 //注:本題存在缺陷,要求O(1)時間,則沒法肯定待刪除結點的確在表中 public class DeleteNodeInList { public class ListNode{ int val; ListNode next; public ListNode(int value,ListNode nextNode) { val=value; next=nextNode; } } /** * 返回值:頭結點 * 返回值不能夠爲void,不然頭結點沒法刪除 * 即:函數中雖然令head=null,但返回到主程序後, * head仍是不變,因此令該函數返回值爲ListNode */ public ListNode deleteNode(ListNode head,ListNode pToBeDeleted) { if(head==null||pToBeDeleted==null) return head; //待刪除結點不是尾結點 if(pToBeDeleted.next!=null) { ListNode nextNode=pToBeDeleted.next; pToBeDeleted.val=nextNode.val; pToBeDeleted.next=nextNode.next; nextNode=null; //只有一個結點(便是尾結點,又是頭結點) }else if(head==pToBeDeleted) { pToBeDeleted=null; head=null; //鏈表含多個結點,刪除尾結點 }else { ListNode preNode=head; while(preNode.next!=pToBeDeleted && preNode!=null) { preNode=preNode.next; } if(preNode==null) { System.out.println("沒法找到待刪除結點!"); return head; } preNode.next=null; pToBeDeleted=null; } return head; } //=========測試代碼========== void test(ListNode head,ListNode PToBeDelete) { System.out.println("============"); System.out.print("The original list is: "); ListNode curr=head; if(curr!=null) { while(curr.next!=null) { System.out.print(curr.val+","); curr=curr.next; } System.out.println(curr.val); }else { System.out.println(); } System.out.print("The node to be deleted is: "); if(PToBeDelete!=null) System.out.println(PToBeDelete.val); else System.out.println(); curr=deleteNode(head, PToBeDelete); System.out.print("The result list is: "); if(curr!=null) { while(curr.next!=null) { System.out.print(curr.val+","); curr=curr.next; } System.out.println(curr.val); }else { System.out.println(); } System.out.println("============"); } /** * 鏈表含多個結點,刪除頭結點 */ void test1() { ListNode p4=new ListNode(4, null); ListNode p3=new ListNode(3, p4); ListNode p2=new ListNode(2, p3); ListNode p1=new ListNode(1, p2); test(p1, p1); } /** * 鏈表含多個結點,刪除中間結點 */ void test2() { ListNode p4=new ListNode(4, null); ListNode p3=new ListNode(3, p4); ListNode p2=new ListNode(2, p3); ListNode p1=new ListNode(1, p2); test(p1, p3); } /** * 鏈表含多個結點,刪除尾結點 */ void test3() { ListNode p4=new ListNode(4, null); ListNode p3=new ListNode(3, p4); ListNode p2=new ListNode(2, p3); ListNode p1=new ListNode(1, p2); test(p1, p4); } /** * 鏈表含一個結點,刪除結點 */ void test4() { ListNode p4=new ListNode(4, null); test(p4, p4); } /** * 鏈表爲空 */ void test5() { test(null, null); } public static void main(String[] args) { DeleteNodeInList demo = new DeleteNodeInList(); demo.test1(); demo.test2(); demo.test3(); demo.test4(); demo.test5(); } }
============ The original list is: 1,2,3,4 The node to be deleted is: 1 The result list is: 2,3,4 ============ ============ The original list is: 1,2,3,4 The node to be deleted is: 3 The result list is: 1,2,4 ============ ============ The original list is: 1,2,3,4 The node to be deleted is: 4 The result list is: 1,2,3 ============ ============ The original list is: 4 The node to be deleted is: 4 The result list is: ============ ============ The original list is: The node to be deleted is: The result list is: ============
1.鏈表中刪除結點的方法中,雖然直接令head=null了,但在主函數中的head仍是不變,所以要令刪除結點的返回值爲ListNode,將返回值賦值給主函數中的head,這樣才能實現真正的刪除。
2.另外一種狀況能夠令刪除函數返回值爲void,只是須要定義一個頭結點head(1中的head至關因而第一個結點),這個頭結點中不存任何數據,僅僅起到指針的做用,第一個結點是頭結點的下一個結點,經過對head.next操做,可以實現真正的刪除。
3.和鏈表有關的特殊狀況:頭結點,尾結點,鏈表僅一個結點,null等。