标签:链表带环问题
1、判断一个单链表是否带环
思路解析:
判断一个单链表是不是带环,就看在遍历单链表的时候能不能遍历完成,如果带环的话会陷入死循环程序一直无法结束,但是这种判断方法在程序的实现是不可能的。所以转换一种思路,利用两个遍历速度不同的指针遍历,如果存在环的话,那么快指针迟早会追上慢指针。通过这个判断程序实现起来是比较简单可行的。
单链表的结构体及其类的定义
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; };
判断单链表是不是存在环
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;//无环 }
2、求取环的长度
思路分析:
在上面已经找到了快慢指针的相遇节点,我们可以通过在相遇的节点处重新遍历,并且引入一个计数器,直到再次到达相遇节点。
int List::GetCircleLength(Node* meet) { Node* start = meet; Node* end = meet; int count = 0;//计数器 do { start = start->_next; count++; } while (start != end); return count; }
3、找到环的入口点
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; }
标签:链表带环问题
原文地址:http://10788311.blog.51cto.com/10778311/1751887