2个链表是否相交

来源:互联网 发布:前端dns优化 编辑:程序博客网 时间:2024/05/17 04:57
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。为了简化问题,我们假设俩个链表均不带环。


问题扩展:


如果链表可能有环列?

如果需要求出俩个链表相交的第一个节点列?

#include <stdio.h>#include <stdlib.h>typedef int Type; /* 字符型数据*/typedef struct LNode {Type data;struct LNode *next;} LNode;LNode* CreateListNode(int value) {LNode* pNode = (LNode *) malloc(sizeof(LNode));pNode->data = value;pNode->next = NULL;return pNode;}void ConnectListNodes(LNode* pCurrent, LNode* pNext) {if (!pCurrent) {printf("Error to connect two nodes.\n");exit(1);}pCurrent->next = pNext;}void DestroyNode(LNode* pNode) {free(pNode);}unsigned int GetListLength(LNode* pHead) {unsigned int nLength = 0;LNode* pNode = pHead;while (pNode != NULL) {++nLength;pNode = pNode->next;}return nLength;}//是否存在环,若存在返回入环点,否则返回空LNode* isExistLoop(LNode *head, LNode **meetPoint) {if (!head) {return NULL;}LNode *inLoopPoint = NULL;LNode *slow = head, *fast = head;while (fast && fast->next) {slow = slow->next;fast = fast->next->next;if (slow == fast) {break;}}if (!fast || !(fast->next)) {return NULL;}*meetPoint = fast;slow = head;while (slow != fast) {slow = slow->next;fast = fast->next;}inLoopPoint = fast;return inLoopPoint;}LNode* getLastNode(LNode* pHead) {LNode *p = pHead;while (p && p->next) {p = p->next;}return p;}/* 均无环,方式1: * 长链表节点先出发前进(lengthMax-lengthMin)步, * 之后两个链表同时前进,每次一步,相遇的第一点 * 即为两个链表相交的第一个点*/LNode* FindFirstCommonNode1(LNode *pHead1, LNode *pHead2) {// 得到两个链表的长度unsigned int nLength1 = GetListLength(pHead1);unsigned int nLength2 = GetListLength(pHead2);int nLengthDif = nLength1 - nLength2;LNode* pListHeadLong = pHead1;LNode* pListHeadShort = pHead2;if (nLength2 > nLength1) {pListHeadLong = pHead2;pListHeadShort = pHead1;nLengthDif = nLength2 - nLength1;}// 先在长链表上走几步,再同时在两个链表上遍历int i;for (i = 0; i < nLengthDif; ++i)pListHeadLong = pListHeadLong->next;//第一个相等的结点while ((pListHeadLong != NULL) && (pListHeadShort != NULL)&& (pListHeadLong != pListHeadShort)) {pListHeadLong = pListHeadLong->next;pListHeadShort = pListHeadShort->next;}// 得到第一个公共结点LNode* pFisrtCommonNode = pListHeadLong;return pFisrtCommonNode;}/* 均无环,,方式2: * 将其中一个链表首尾相连, * 判断另一个链表是否存在环, * 如果存在,则两个链表相交, * 且找出来的环入口点即为相交的第一个点 */LNode* FindFirstCommonNode2(LNode* pHead1, LNode* pHead2) {LNode *meetPoint = NULL, *inLoopPoint;if (!isExistLoop(pHead1, &meetPoint) && !isExistLoop(pHead2, &meetPoint)) {LNode *lastNode = getLastNode(pHead1);//头尾相接制造环lastNode->next = pHead1;}//若相交, pHead2定会出现环return isExistLoop(pHead2, &meetPoint);}/*均有环 * 我们能够分别找出两个链表的相遇点pos1, pos2, * 然后还是使用两个指针fast和slow,都初始化为pos1, * 且fast每次前进2步,slow每次前进1步。 * 若fast指针在遇到slow前,出现fast等于pos2或fast->next等于pos2, * 则说明两个链表相交,否则不相交。若两链表相交, * 我们可知pos2肯定是两个链表的一个相交点, * 将这个点看做两个链表的终止节点,使用(3)中的解法, * 即可找到两个链表相交的第一个节点。 * */LNode* FindFirstCommonNode3(LNode* pHead1, LNode* pHead2) {LNode *meetPoint1 = NULL, *meetPoint2 = NULL;LNode *fast = NULL, *slow = NULL;if (isExistLoop(pHead1, &meetPoint1) && isExistLoop(pHead2, &meetPoint2)) {fast = meetPoint1;slow = meetPoint1;do {if (fast == meetPoint2 || fast->next == meetPoint2) {break;}fast = fast->next->next;slow = slow->next;} while (fast != slow);if (fast != meetPoint2 && fast->next != meetPoint2) {//printf("Failed.\n");return NULL;} else {int len1 = 0, len2 = 0;LNode *longHead = pHead1, *shortHead = pHead2;while (longHead->next != meetPoint2) {len1++;longHead = longHead->next;}while (shortHead->next != meetPoint2) {len2++;shortHead = shortHead->next;}int lenDif = len1 - len2;//指针重置至起点longHead = pHead1;shortHead = pHead2;if (len2 > len1) {longHead = pHead2;shortHead = pHead1;lenDif = len2 - len1;}// 先在长链表上走几步,再同时在两个链表上遍历int i;for (i = 0; i < lenDif; ++i)longHead = longHead->next;//第一个相等的结点while ((longHead != NULL) && (shortHead != NULL)&& (longHead != shortHead)) {longHead = longHead->next;shortHead = shortHead->next;}// 得到第一个公共结点LNode* pFisrtCommonNode = longHead;//printf("first common node:%3d", *pFisrtCommonNode);return pFisrtCommonNode;}}}LNode* FindFirstCommonNode(LNode* pHead1, LNode* pHead2) {if (!pHead1 || !pHead2) {return NULL;}LNode *meetPoint1 = NULL, *meetPoint2 = NULL;//一个有环,另一个无环,必无公共点if ((!isExistLoop(pHead1, &meetPoint1) && isExistLoop(pHead2, &meetPoint2))|| (isExistLoop(pHead1, &meetPoint1)&& !isExistLoop(pHead2, &meetPoint2))) {return NULL;}//均无环if (!isExistLoop(pHead1, &meetPoint1)&& !isExistLoop(pHead2, &meetPoint2)) {return FindFirstCommonNode1(pHead1, pHead2);//return FindFirstCommonNode2(pHead1, pHead2);}//均有环if (isExistLoop(pHead1, &meetPoint1) && isExistLoop(pHead2, &meetPoint2)) {return FindFirstCommonNode3(pHead1, pHead2);}}void Test(char* testName, LNode* pHead1, LNode* pHead2, LNode* pExpected) {if (testName != NULL)printf("%s begins: ", testName);LNode* pResult = FindFirstCommonNode(pHead1, pHead2);if (pResult == pExpected)printf("first common node:%-3dPassed.\n", *pResult);elseprintf("Failed.\n");}//无环void Test1() {LNode* pNode1 = CreateListNode(1);LNode* pNode2 = CreateListNode(2);LNode* pNode3 = CreateListNode(3);LNode* pNode4 = CreateListNode(4);LNode* pNode5 = CreateListNode(5);LNode* pNode6 = CreateListNode(6);LNode* pNode7 = CreateListNode(7);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode6);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);Test("Test1", pNode1, pNode4, pNode6);DestroyNode(pNode1);DestroyNode(pNode2);DestroyNode(pNode3);DestroyNode(pNode4);DestroyNode(pNode5);DestroyNode(pNode6);DestroyNode(pNode7);}//均有环void Test2() {LNode* pNode1 = CreateListNode(1);LNode* pNode2 = CreateListNode(2);LNode* pNode3 = CreateListNode(3);LNode* pNode4 = CreateListNode(4);LNode* pNode5 = CreateListNode(5);LNode* pNode6 = CreateListNode(6);LNode* pNode7 = CreateListNode(7);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode6);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);//制造环ConnectListNodes(pNode7, pNode4);Test("Test2", pNode1, pNode4, pNode6);DestroyNode(pNode1);DestroyNode(pNode2);DestroyNode(pNode3);DestroyNode(pNode4);DestroyNode(pNode5);DestroyNode(pNode6);DestroyNode(pNode7);}int main(void) {setvbuf(stdout, NULL, _IONBF, 0);Test1();return EXIT_SUCCESS;}


0 0