求帶環的單鏈表入口位置處的節點

題目:如本文題目,給定一個帶環的單鏈表,給出一個算法求鏈表環的入口位置處的節點。


解析:這題的解決步驟如下:

1.設置一個快指針fast和一個慢指針slow,它們同時從鏈表頭開始往後遍歷,快指針每次移動兩個位置,慢指針每次移動一個位置

2.當快指針和慢指針相遇時,將慢指針重新指向鏈表頭

3.快指針和慢指針此時在同時移動,兩個指針都一次移動一個位置,當兩個指針再次相遇時,指針所指的節點即入口節點。

之所以這樣能夠定位環的入口節點,原因解析如下:

假設鏈表頭節點爲head,環入口節點爲entrance,並假設有head到entrance共有n個節點(包括head,

但不包括entrance),環的節點個數爲m。我們知道,快指針和慢指針第一次相遇的節點肯定在環中,

假設從entrance到這個節點共k個節點(包括entrance和相遇的節點)。那麼此時slow指針共移動了 

n+k 個節點,fast指針共移動了 2*(n+k) 個節點。則有 2*(n+k) = n + k + x*m,其中x

表示此時fast指針已經在環中繞的圈數。由此可以得到 n+k=x*m,即 n = (x-1)*m + m - k

。那麼此時再將慢指針重新指向head,並且slow指針和fast指針均以同樣的速度,每次移動一個節點

位置往後移動,那麼當slow指針走到entrance時,fast指針同樣移動到了entrance節點。

代碼如下:
SListNode* FindBeginning(SListNode* head)
{
	if (head == NULL)
	{
		return NULL;
	}
	SListNode* fast = head;
	SListNode* slow = head;
	while (1)
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast == slow)
		{
			break;
		}
	}
	slow = head;
	while (fast != slow)
	{
		fast = fast->next;
		slow = slow->next;
	}

	return fast;
}

測試用例如下:

void Test14()
{

		SListNode *seq = NULL;
	
		PushBack(seq, 1);
		PushBack(seq, 2);
		PushBack(seq, 3);
		PushBack(seq, 4);
		PushBack(seq, 5);
		PushBack(seq, 6);
		PushBack(seq, 7);
		PushBack(seq, 8);
		PushBack(seq, 9);
		PushBack(seq, 10);
		
		SListNode * address1 = Find(seq, 10); //將節點10的地址返回給address1
		SListNode * address2 = Find(seq, 6);  //將節點6的地址返回給address2
		address1->next = address2;      //節點10就會指向節點6,這樣就形成一個環
		
		SListNode* ret=FindBeginning(seq);  //利用函數返回環入口節點地址給ret

		cout << "入口節點是 "<<ret->date << endl;  //輸出環入口節點的數據
	
}

運行結果如下:

wKioL1bZIluDwPk2AAAR-IVB7Ow411.png










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