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


本文參考自《劍指offer》一書,代碼采用Java語言。

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

題目

  給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該結點。

思路

  通常那樣從頭開始查找刪除需要的時間為O(n),要在O(1)時間刪除某結點,可以這樣實現:設待刪除結點i的下一個結點為j,把j的值復制到i,再把i的指針指向j的下一個結點,最后刪除j,效果就相當於刪除j。

  注意特殊情況:1.當待刪除結點i為尾結點時,無下一個結點,則只能從頭到尾順序遍歷;2.當鏈表中只有一個結點時(即是頭結點,又是尾結點),必須把頭結點也設置為null。

  本題有個缺陷:要求O(1)時間刪除,相當於隱藏了一個假設:待刪除的結點的確在表中

測試算例

  1.功能測試(多個結點鏈表,刪除頭結點、中間結點和尾結點;單個結點鏈表)

  2.特殊測試(頭結點或刪除結點為null)

完整Java代碼

(含測試代碼)

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實現合集  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM