【Java】 劍指offer(17) 在O(1)時間刪除鏈表結點

本文參考自《劍指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

完整Java代碼

(含測試代碼)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: 
============
DeleteNodeInList

 

收穫

  1.鏈表中刪除結點的方法中,雖然直接令head=null了,但在主函數中的head仍是不變,所以要令刪除結點的返回值爲ListNode,將返回值賦值給主函數中的head,這樣才能實現真正的刪除。

  2.另外一種狀況能夠令刪除函數返回值爲void,只是須要定義一個頭結點head(1中的head至關因而第一個結點),這個頭結點中不存任何數據,僅僅起到指針的做用,第一個結點是頭結點的下一個結點,經過對head.next操做,可以實現真正的刪除。

  3.和鏈表有關的特殊狀況:頭結點,尾結點,鏈表僅一個結點,null等。

 

更多:《劍指Offer》Java實現合集 

相關文章
相關標籤/搜索