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;
}