第一部分——判断单个链表是否有环
使用两个指针,一个快指针,一个慢指针,快指针一次走两步,慢指针一次走一步;
若快指针最后变为空,则单链表为无环单链表,返回空指针;
若快慢指针在某一时刻指向同一节点,即二者完全一样,则为有环单链表,
此时让快指针重新指向链表头结点,然后快慢指针均一次走一步,
当快慢指针再次相同时,则此节点即为链表入环节点,将其返回。
第二部分——判断链表是否相交
情况一:两链表中一个为有环链表,一个为无环链表,则此时两链表一定不相交,返回空即可;
情况二:两个链表都是无环链表,此时有两种情况,1)两个无环链表相交;2)两个无环链表不相交;
首先遍历两链表,分别得到两个链表的长度,
取两个长度的差值,然后让长链表先遍历差值长度,此时长链表剩余部分与短链表长度相同,
然后两条链表同时遍历,直到遇到相同节点为止,若相同节点为空,则两链表不相交,返回空,
否则两链表相交,返回相交节点即可;
情况三:两个链表都是有环链表,此时有三种情况,1)两个有环链表不相交;2)两个有环链表相交,且交点在环外;3)两个有环链表相交,且交点在环内。
首先获得两个链表的入环节点,若入环节点相同,则可转变为情况二,此时将入环节点作为链表的终止节点即可;若两个入环节点不同,以一个入环节点开始遍历,若遍历一遍过程中都没有遇见另一个入环节点,则两链表不相交,返回空,若遇到另一入环节点,则说明两链表相交,此时返回任意一个入环节点即可。
其他文章:https://blog.csdn.net/computer_user/article/details/86833392
https://blog.csdn.net/qq_30024069/article/details/96428037
https://blog.csdn.net/fangfang_666/article/details/76045987
struct ListNode
{
int value;
struct ListNode* next;
ListNode(int v = 0) :value(v), next(nullptr) {}
};
//判断是否有环,如果有环,返回环结点入口,如果没有环,则返回nullptr
ListNode* isLoop(ListNode* head)
{
if (head == nullptr || head->next == nullptr||head->next->next==nullptr)
return nullptr;
ListNode* slow = head->next; //慢指针走一步
ListNode* fast = head->next->next; //快指针走俩步
while (slow != fast)
{
slow = slow->next;
fast = fast->next->next;
if (slow->next == nullptr || fast->next == nullptr)
return nullptr;
}
fast = head; //fast指针回到原点
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
//计算带环链表的长度
int loopLength(ListNode* head, ListNode* enterLoop)
{
int count = 1; //代表头结点长度为1
while (head != enterLoop)
{
count++;
head = head->next;
}
ListNode* cur = enterLoop->next;
while (cur != enterLoop)
{
count++;
cur = cur->next;
}
return count;
}
//计算无环链表的长度
int noloopLength(ListNode* head)
{
int count = 0;
if (head == nullptr)
return count;
while (head != nullptr)
{
count++;
head = head->next;
}
return count;
}
//计算指定俩个结点之间的长度
int calculateCount(ListNode* first, ListNode* second)
{
int count = 0;
while (first != second)
{
count++;
first = first->next;
}
return count;
}
//判断俩个无环链表是否有公共结点(是否相交)
ListNode* noloopListMeet(ListNode* head1, int len1, ListNode* head2, int len2)
{
if (len1 < len2)
swap(head1, head2);
int k = abs(len1 - len2); //计算出俩个链表之间的差值
//让长的那个链表先走完差值
while (k--)
head1 = head1->next;
while (head1 != head2) //都为nullptr或者有公共结点时退出
{
head1 = head1->next;
head2 = head2->next;
}
return head1;
}
//判断俩个有环链表是否有公共结点(是否相交)
ListNode* loopListMeet(ListNode* head1, ListNode* loop1, ListNode* head2, ListNode* loop2)
{
if (loop1 == loop2) //俩个有环链表的入口结点相同
{
return noloopListMeet(head1, calculateCount(head1, loop1), head2, calculateCount(head2, loop2));
}
else //否则看看环中是否能相交
{
ListNode* temp = loop1;
loop1 = loop1->next;
while (temp != loop1&&temp != loop2)
{
temp = temp->next;
}
if (temp == loop2)
return temp;
else
return nullptr;
}
}
int main()
{
ListNode* node1 = new ListNode(1);
ListNode* node2 = new ListNode(2);
ListNode* node3 = new ListNode(3);
ListNode* node4 = new ListNode(4);
ListNode* node5 = new ListNode(5);
ListNode* node6 = new ListNode(6);
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node5;
node5->next = node6;
node6->next = node2;
ListNode* node = isLoop(node1);
if (node)
{
cout << "环入口值为:"<<node->value << endl;
cout << "带环链表长度为:" << loopLength(node1, node) << endl;
}
ListNode* node7 = new ListNode(7);
ListNode* node8 = new ListNode(8);
ListNode* node9 = new ListNode(9);
ListNode* node10 = new ListNode(10);
ListNode* node11 = new ListNode(11);
ListNode* node12 = new ListNode(12);
ListNode* node13 = new ListNode(13);
ListNode* node14 = new ListNode(14);
node13->next = node14; //用于测试俩个不相交的无环链表
node7->next = node8;
node8->next = node9;
node9->next = node10;
node10->next = node11;
node12->next = node10;
ListNode* cross = noloopListMeet(node7, noloopLength(node7), node12, noloopLength(node12));
if (cross)
cout << "公共结点为:" << cross->value << endl;
else
cout << "俩个链表不相交" << endl;
}