c/c++單鏈表面試題—鏈表帶環問題

一、判斷一個單鏈表是否帶環ide

思路解析:spa

判斷一個單鏈表是否是帶環,就看在遍歷單鏈表的時候能不能遍歷完成,若是帶環的話會陷入死循環程序一直沒法結束,可是這種判斷方法在程序的實現是不可能的。因此轉換一種思路,利用兩個遍歷速度不一樣的指針遍歷,若是存在環的話,那麼快指針早晚會追上慢指針。經過這個判斷程序實現起來是比較簡單可行的。指針

單鏈表的結構體及其類的定義orm

struct Node
{
public:
	Node(const DataType& d)
		:_data(d)
		,_next(NULL)
	{}
public:
	DataType _data;
	Node* _next;
};

class List
{
public:
	List()
		:_head(NULL)
		,_tail(NULL)
	{}

	~List()
	{
		Node* cur = _head;
		while (cur && cur!=_tail)
		{
			Node* del = cur;
			cur = cur->_next;
			delete del;
		}
		delete _tail;//由於若是存在環的話尾指針的next域不爲空會使
		_head = NULL;//環入口點析構兩次,致使程序崩潰
		_tail = NULL;
	}
private:
	Node* _head;
	Node* _tail;
};

判斷單鏈表是否是存在環
it

Node*  List::CheckCycle()
{
	Node* slow = _head;//慢指針
	Node* fast = _head;//快指針
	while (fast && fast->_next)
	{
		slow = slow->_next;
		fast = fast->_next->_next;
		if (fast == slow)
		{
			return slow;//有環返回相遇的節點
		}
	}
	return NULL;//無環
}

二、求取環的長度ast

思路分析:class

在上面已經找到了快慢指針的相遇節點,咱們能夠經過在相遇的節點處從新遍歷,而且引入一個計數器,直到再次到達相遇節點。List

int  List::GetCircleLength(Node* meet)
{
	Node* start = meet;
	Node* end = meet;
	int count = 0;//計數器
	do
	{
		start = start->_next;
		count++;
	} while (start != end);
	return count;
}

三、找到環的入口點循環

1)一個指針從相遇的節點開始遍歷,另一個從頭開始遍歷直到兩個指針相遇,便是入口點。遍歷

Node*  List::GetCycleEntryNode(Node* meetNode)
{
	Node* start = _head;
	Node* end = meetNode;
	while (start != end)
	{
		start = start->_next;
		end = end->_next;
	}

	return start;
}

2)將環在快慢指針相遇節點的下一個節點拆分紅兩個鏈表,使得這個問題既可轉化爲鏈表的相交問題,鏈表的交點便是環入口點。

Node*  List::GetCycleEntryNode(Node* meetNode)
{
	Node *l1 = _head;
	Node *l2 = meetNode->_next;//從相遇節點的下一個節點開始
	meetNode->_next = NULL;//將兩條單鏈表的尾節點的_next域賦爲空
	Node *Enter = GetCrossNode(l1, l2);//將單鏈表拆分紅兩條並找交點
	meetNode->_next = l2;//將原始的單鏈表恢復
	return Enter;
}
相關文章
相關標籤/搜索