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,"拷贝后链表"); }
运行结果: