明天的问题尚未知晓就为之焦虑,昨天的问题已然完结仍无法释怀。生命在于发展,如果害怕新的东西,停滞不前,那么我们就是在拒绝生命。
——摘自 奥格.曼狄诺《羊皮卷》
第7 题
微软亚院之编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
4
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?
解题要点:
1.判断是否带有环;
2.若是不带环,两种判断相交的方法,利用环找到相交点;
3.若是带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。如果在,则相交,如果不在,则不相交。
#include <iostream>
#include<assert.h>
using namespace std;
class Node{
public:
Node(int d):data(d), next(NULL){}
int data;
Node* next;
};
void displayLinkList(Node* head, int n)
{
assert(head!=NULL);/*细节但很重要的入参检查;*/
n = n+3;/*为什么这里要加上一个数值呢?为了方便从输出结果验证链表是否带环阿!*/
for (int i = 0; i < n && head; i++, head = head->next)
{
cout << head->data << " ";
}
cout << endl;
}
/*判断是否是带环链表.并且找出环的入口节点*/
Node* findLoopPort(Node* head)
{
Node* fast = head;
Node* slow = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(fast==NULL || fast->next==NULL)/*链表不带环*/
{
return NULL;
}
if (slow == fast)/*fast与slow两个指针相遇,该链表带有环*/
break;
}
slow = head;/*fast指针从交点出发,slow从头指针出发,再次相遇为环的入口*/
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;/*slow指向环的入口*/
}
void IsExitLoop(Node *head, int n)
{
displayLinkList(head, n);
Node *result = findLoopPort(head);
if (result!=NULL)
{
cout << "head has loop,loop port is :"<<result->data << endl;
}
else
{
cout << "head does not have loop" << endl;
}
}
/*,两个不带环的单链表,将其中一个单链表形成环,判断另一个是否有环,没有环则不相交;两个单链表若是有相交,则从相交点到尾节点都相同*/
Node* intersect3(Node *head1, Node *head2)
{
assert(head1!=NULL && head2!=NULL);
Node* tail2 = head2;
while (tail2->next)
tail2 = tail2->next;
tail2->next = head2;
Node* result = findLoopPort(head1);
tail2->next = NULL;
return result;
}
void testIntersect3(Node *head1, Node *head2)
{
if (intersect3(head1, head2)!=NULL)
cout << "intersect" << endl;
else
cout << "not intersect" << endl;
}
/*两个不带环的单链表,若他们的尾指针相同,则相交,时间复杂的o(head1.length+head2.length),o(n)级别,空间复杂的o(1)*/
bool intersect4(Node *head1, Node *head2)
{
assert(head1!=NULL && head2!=NULL);
Node *tail1 = head1;
Node *tail2 = head2;
while (tail1->next)
tail1 = tail1->next;
while (tail2->next)
tail2 = tail2->next;
return tail1 == tail2;
}
void testIntersect4(Node *head1, Node *head2)
{
if (intersect4(head1, head2))
cout << "intersect" << endl;
else
cout << "not intersect" << endl;
}
/*找到两个链表相交点*/
Node *findFirstIntersection(Node *head1, Node *head2)
{
assert(head1!=NULL && head2!=NULL);
int len1 = 1;
int len2 = 1;
bool result = false;
Node *p = head1;
Node *q = head2;
while (p->next)
{
len1 ++;
p = p->next;
}
while (q->next)
{
len2 ++;
q = q->next;
}
result = (p == q);
if (result)/*倘若两个链表的长度不相等*/
{
int steps = abs(len1 - len2);
Node *head = (len1 > len2) ? head1 : head2;
while (steps!=0)
{
head = head->next;
steps --;
}
/*head指向长的链表,并且先行steps步长*/
(len1 > len2) ? (p = head, q = head2) : (p = head1, q = head);
while (p != q)/*此后,两个指针再相遇点为第一个交点*/
{
p = p->next;
q = q->next;
}
return p;
}
return NULL;
}
void testFindFirstIntersection(Node* head1, Node* head2)
{
Node* result = findFirstIntersection(head1, head2);
if (result == NULL)
{
cout << "no intersection" << endl;
}
else
{
cout << "first intersection is " << result->data << endl;
}
}
int main()
{
int i;
Node *head1 = NULL;
Node *head2 = NULL;
/*create a cyclelink:head1*/
Node *tail = NULL;
for (i = 0; i < 10; i ++)
{
Node *p = new Node(i + 1);
if (head1 == NULL)
{
head1 = p;
tail = head1;
}
else
{
tail->next = p;
tail = p;
}
}
Node *p = head1;
for (i = 1; i < 5; i ++)
p = p->next;
tail->next = p;
/*create a link withou cycle*/
tail = NULL;
for (i = 0; i < 10; i ++)
{
Node *p = new Node(i + 1);
if (head2 == NULL)
{
head2 = p;
}
else
{
tail->next = p;
}
tail = p;
}
IsExitLoop(head1, 10);
IsExitLoop(head2, 10);
/*another mothod to create links*/
Node *head3 = NULL;
Node *head4 = NULL;
Node *p1 = new Node(1);
Node *p2 = new Node(2);
Node *p3 = new Node(3);
Node *p4 = new Node(4);
Node *p5 = new Node(5);
Node *p11 = new Node(11);
Node *p12 = new Node(12);
Node *p13 = new Node(13);
Node *p14 = new Node(14);
Node *p15 = new Node(15);
head3 = p1;
p1->next = p2;
p2->next = p3;
p3->next = p4;
p4->next = p5;
head4 = p11;
p11->next = p12;
p12->next = p13;
p13->next = p14;
/*此时,两个链表相交*/
p14->next=p3;
p15->next = p13;
testIntersect3(head3, head4);
testIntersect4(head3, head4);
testFindFirstIntersection(head3, head4);
/*此时,两个链表不相交*/
p14->next=p15;
p15->next = NULL;
testIntersect3(head3, head4);
testIntersect4(head3, head4);
testFindFirstIntersection(head3, head4);
delete p;
delete p1;
delete p2;
delete p3;
delete p4;
delete p5;
delete p11;
delete p12;
delete p13;
delete p14;
delete p15;
return 1;
}