1.判定两个链表是否相交, 并求出交点
解题思路:
两链表若相交,则其最后一个节点必定相同。所以遍历得出两链表的尾节点可得知两链表是否相交。
若两链表相交,则求出两链表长度,相减得其差值len。
较长链表先向后遍历len次,随后两链表同时向后遍历。直到出现两值相同时,该节点即为相交点。
//判定两个链表是否相交, 并求出交点
LinkNode* HasCross(LinkNode* head1, LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return NULL;
}
int len1 = 0,len2 = 0,len = 0;
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
while(cur1)
{
len1++;
cur1 = cur1->next;
}
while(cur2)
{
len2++;
cur2 = cur2->next;
}
if(len1 > len2)
{
len = len1 - len2;
while(len--)
{
cur1 = cur1->next;
}
}
else
{
len = len2-len1;
while(len--)
{
head2 = head2->next;
}
}
while(head1 != head2)
{
head1 = head1->next;
head2 = head2->next;
}
return head1;
}
//测试函数
void TestHasCross()
{
TITLE;
LinkNode* head,*head2;
LinkListInit(&head);
LinkListInit(&head2);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkListPushBack(&head2,'h');
LinkListPushBack(&head2,'i');
LinkListPushBack(&head2,'j');
LinkListPushBack(&head2,'k');
LinkNode* pos1 = LinkListFind(head,'d');
LinkNode* pos2 = LinkListFind(head2,'k');
pos2->next = pos1;
LinkListPrint(head,"单链表head1");
LinkListPrint(head2,"单链表head2");
LinkNode* ret = HasCross(head,head2);
printf("两元素相交于d\n");
printf("expect is d,actul is %c\n",ret->data);
}
运行结果:
2.判定两个链表是否相交. 但是链表可能带环
可分为三种情况:
1.两个不带环链表,上一题已经解决
2.一个带环,一个不带环
不可能相交
3.两个带环链表,可分为以下两种情况
两带环链表是否相交判断方法:
我们可以先分别求出两环快慢指针的相遇点meet(快指针一次走2步,慢指针一次走1步)。
随后用其中一个meet点绕环一周,若能遇到另一个meet点则两链表相交。
反之,两链表不相交。
int HasCrossWithCycle(LinkNode* head1, LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return 0;
}
int ret1 = HasCycle(head1);
int ret2 = HasCycle(head2);
if(ret1 == 0 && ret2 == 0)
{
//表示两链表都不带环
LinkNode* ret = HasCross(head1,head2);
if(ret != NULL)
//两链表相交
return 1;
else
//两链表不相交
return 0;
}
else if(ret1 == 1 && ret2 == 1)
{
LinkNode* MeetNode1 = GetMeetNode(head1);
LinkNode* cur = MeetNode1;
LinkNode* MeetNode2 = GetMeetNode(head2);
while(cur->next != MeetNode1)
{
if(cur == MeetNode2)
{
//表示两环相交
return 1;
}
cur = cur->next;
}
return 0;
}
else
{
//表示一个链表带环,一个链表不带环
//此时,两链表不可能相交
return 0;
}
}
运行结果:
3. 求两个有序链表的交集
解题思路:
从头节点开始,比较当前两节点大小。
若相等,将该节的值点插入新链表,两链表同时向后走一步。
若不相等,将较小值的链表向后走一步。(因为是有序链表,所以node1小于node2的话,node1一定小于node2后面的节点,不可能出现相等的情况。)
//求两个有序链表的交集,返回表示交集的新链表
//小的值往后移,相等都往后移
LinkNode* UnionSet(LinkNode* head1, LinkNode* head2)
{
LinkNode* newHead;
LinkListInit(&newHead);
while(head1 && head2)
{
if(head1->data < head2->data)
head1 = head1->next;
else if(head1->data > head2->data)
head2 = head2->next;
else
{
//两值相等,加入新链表
LinkListPushBack(&newHead,head1->data);
head1 = head1->next;
head2 = head2->next;
}
}
return newHead;
}
//测试函数
void TestUnionSet()
{
TITLE;
LinkNode* head,*head2,*ret;
LinkListInit(&head);
LinkListInit(&head2);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkListPushBack(&head2,'b');
LinkListPushBack(&head2,'d');
LinkListPushBack(&head2,'r');
LinkListPushBack(&head2,'z');
LinkListPrint(head,"单链表head1");
LinkListPrint(head2,"单链表head2");
ret = UnionSet(head,head2);
LinkListPrint(ret,"两链表交集为");
}
运行结果:
4.拷贝复杂链表
//拷贝复杂链表
typedef struct ComplexNode
{
DataType data;
struct ComplexNode* next;
struct ComplexNode* random;
}ComplexNode;
ComplexNode* CreateComplexNode(DataType data)
{
ComplexNode* newNode = (ComplexNode*)malloc(sizeof(ComplexNode));
if(newNode == NULL)
{
printf("申请失败\n");
return NULL;
}
newNode->data = data;
newNode->next = NULL;
newNode->random = NULL;
return newNode;
}
//打印复杂链表
void ComplexNodePrint(ComplexNode* head,char* msg)
{
printf("[%s]\n",msg);
ComplexNode* cur = head;
while(cur)
{
printf("%c ",cur->data);
cur = cur->next;
}
printf("\n[random]\n");
cur = head;
while(cur)
{
if(cur->random == NULL)
{
printf("[%c->NULL] ",cur->data);
cur = cur->next;
continue;
}
printf("[%c->%c] ",cur->data,cur->random->data);
cur = cur->next;
}
printf("\n");
}
//拷贝复杂链表
ComplexNode* CopyComplex(ComplexNode* head)
{
if(head == NULL)
{
return;
}
ComplexNode* cur = head;
//此循环,是将原链表后每个节点插入新节点
while(cur)
{
ComplexNode* newNode = CreateComplexNode(cur->data);
newNode->next = cur->next;
cur->next = newNode;
cur = newNode->next;
}
cur = head;
ComplexNode* newNode = NULL;
//此循环,是给新插入的节点的随机指针域赋值
while(cur)
{
newNode = cur->next;
if(cur->random)
{
newNode->random = cur->random->next;
}
cur = newNode->next;
}
cur = head;
ComplexNode* newHead = cur->next;
ComplexNode* x = head;
//此循环,是将插入的节点从原链表拆分下来,形成新链表完成拷贝
while(cur->next)
{
cur = cur->next;
x->next = cur->next;
x = cur;
}
return newHead;
}
测试函数:
void TestComplexNode()
{
TITLE;
ComplexNode* head;
ComplexNode* a = CreateNode('a');
ComplexNode* b = CreateNode('b');
ComplexNode* c = CreateNode('c');
ComplexNode* d = CreateNode('d');
head = a;
a->next = b;
b->next = c;
c->next = d;
d->next = NULL;
a->random = c;
b->random = d;
c->random = a;
d->random = NULL;
ComplexNodePrint(head,"原链表");
ComplexNode* newNode = CopyComplex(head);
ComplexNodePrint(head,"拷贝后链表");
}
运行结果: