面試題-----在O(1)時間刪除鏈表結點

題目要求

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

題目分析

首先我看到這個題目,還是會慣性思維,認爲刪除指定結點,不就是要遍歷該鏈表找到該結點,那就是O(n)呀。。。(無力吐槽我的智商)仔細思考一下,該函數已經給了兩個已知的參數了,頭節點以及待刪除結點。知道待刪除結點,也就等於知道了該結點的下一個結點。分析到這裏,問題似乎可以解決了,刪除該結點,即就是釋放該結點的空間,斷開該結點與它前面以及後面結點的鏈,看到這裏還不明白的話,可以畫畫圖。


先考慮最簡單的一種情況,如果我們要在圖示的這條鏈表中刪除值c所在的結點,那麼知道函數中所給的該結點,就可以將該結點的next結點中的值拷貝給該結點,如下圖所示,將c覆蓋,然後再將要刪除的c結點的next指向原來的d結點的下一結點,圖中即爲尾結點tail。然後再釋放圖中的d結點。這樣就間接的刪除了待刪除的C結點,此時的時間複雜度爲O(1)。 (歡呼,我們做到了。。)


上面的方案似乎是很可行的,但是是不是真的完全正確那?思考一下,1)假如該鏈表中就只有一個頭結點,上述方案就不可行了,若恰好待刪除結點是頭結點,那麼正好我們可以碰巧刪除它,並且記得最後一定要將頭結點置空;2)假如鏈表有頭有尾,我們要刪除尾結點吶,此時也就只能遍歷整個鏈表找到該結點並刪除,時間複雜度爲O(n)。

考慮到這裏,以爲要大功告成了,然而並沒有。有沒有考慮過對整個函數的思考過程完全建立在一種理想的情況下,那就是我們天真的以爲要刪除的結點在我們的鏈表裏,所以我們是不是應該首先判斷該結點有沒有在鏈表中。但是問題又來了(心好累),查找結點必然是要遍歷該鏈表,時間複雜度必定爲O(n),看來這條路我們無法對它做出什麼優化了,所以爲了完成該題目,只能假設用戶輸入的待刪除結點確確實實在我們的鏈表中,這個責任就交給該函數的調用者吧。

綜上核心代碼:

void DeleteNode(NODE **head,NODE *ToBeDelete)
{
	if(head == NULL || ToBeDelete == NULL)
		return;

	if(ToBeDelete->next != NULL)
	{
		NODE *tmp = ToBeDelete->next;
		ToBeDelete->data = tmp->data;
		ToBeDelete->next = tmp->next;

		delete tmp;
		tmp = NULL;
	}
	else if(ToBeDelete == *head)
	{
		delete ToBeDelete;
		ToBeDelete = NULL;
		*head = NULL;
	}
	else
	{
		NODE *tmp = *head;
		while (tmp != ToBeDelete)
		{
			tmp = tmp->next;
		}

		tmp->next = NULL;
		delete ToBeDelete;
		ToBeDelete = NULL;
	}
}

做不到完美,也要做到近似完美。總體的時間複雜度爲【O(N)*(N-1)+O(n)*1】/n,結果爲O(n).

總結

連自己都看不太懂並且無法說服自己的代碼,還怎麼給別人看。我覺得優秀的編程就是寫出來的程序能很容易的讀懂,所以努力嘍


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章