一、判斷一個單鏈表是否帶環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; }