单向链表相交的第一个公共结点, 判断链表是否有环以及环的入口节点
2013-06-12 22:21
696 查看
//////题目:两个单向链表,找出它们的第一个公共结点。 ////// //////链表的结点定义为: ////// //////struct ListNode ////// //////{ ////// ////// int m_nKey; ////// ////// ListNode* m_pNext; ////// //////}; ////// //////分析:这是一道微软的面试题。微软非常喜欢与链表相关的题目,因此在微软的面试题中,链表出现的概率相当高。 //////如果两个单向链表有公共的结点,也就是说两个链表从某一结点开始,它们的m_pNext都指向同一个结点。 //////但由于是单向链表的结点,每个结点只有一个m_pNext,因此从第一个公共结点开始, //////之后它们所有结点都是重合的,不可能再出现分叉。所以,两个有公共结点而部分重合的链表, //////拓扑形状看起来像一个Y,而不可能像X。 #include <iostream> #include <algorithm> using namespace std; #define NSIZ 101 struct ListNode { int m_nKey; ListNode* m_pNext; }; //获得链表长度 int GetListLength(ListNode * head) { if(!head) { return 0; } int len = 0; ListNode * tmp = head; while(tmp) { ++len; tmp = tmp->m_pNext; } return len; } //尾插法构造链表 void CreateList(ListNode * & head, int arr[], int n) { ListNode * p = head; if(head == 0) { head = new ListNode(); head->m_nKey = arr[0]; p = head; } int i = 1; for(;i < n; ++i) { ListNode * tmp = new ListNode(); tmp->m_nKey = arr[i]; p->m_pNext = tmp; p = tmp; } p->m_pNext = 0; } //合并2个链表 ListNode* UnionList(ListNode * head1, ListNode * head2) { if(head1 == 0 && head2) { return head2; } else if(head1 && !head2) { return head1; } else if(head1 && head2) { ListNode * pre = head1; ListNode * p = pre->m_pNext; while(p) { pre = p; p = p->m_pNext; } pre->m_pNext = head2; return head1; } else { return 0; } } //打印链表元素值 void dump(ListNode * head) { ListNode * p = head; while(p) { printf("%d ", p->m_nKey); p = p->m_pNext; } printf("\n"); } //判断两个链表是否有交点,如果有则返回第一个交点 //如果head1 && head1 == head2那么显然相交,返回head1 //否则 分别获得head1链表和head2链表的长度为len1和len2 ,并且假设len1 > len2 //然后用指针pLong从head1开始向后移sub = len1 - len2步,指针pShort = head2 //然后p1,p2每次前进一步并且比较p1 == p2,若不为空且相等则返回p1, //否则说明head1链表和head2链表没有交点 ListNode * FirstCommonNode(ListNode * head1, ListNode * head2) { int len1 = GetListLength(head1); int len2 = GetListLength(head2); ListNode * Short = head1, *Long = head2; int sub = len2 - len1; if (len1 > len2) { Short = head2; Long = head1; sub = len1 - len2; } while(sub > 0) { Long = Long->m_pNext; --sub; } while(Short && Long && Short != Long) { Short = Short->m_pNext; Long = Long->m_pNext; } if (Short && Long && Short == Long) { return Short; } return 0; } //检测链表中是否有环,快慢指针方法 //若有环则返回从头结点进入环的第一个节点 //假设p1 = head1, p2 = head->next->next //首先检查是否有环,有环的话p1,p2必然在环内相遇 //此时从相遇处端口,方法为 //common = p2; //head2 = p2->next, p2 ->next= 0; //此时原链表被分成了2个链表,头结点分别为head1, head2 //利用FirstCommonNode(ListNode * head1, ListNode * head2)函数得到相交节点FirtNode //然后修复链表:common->next= head2 //最后返回FirstNode ListNode * HasLoop(ListNode * head) { if (!head) { return 0; } ListNode * slow = head; ListNode * quick = head; while(quick && quick->m_pNext) { slow = slow->m_pNext; quick = quick->m_pNext->m_pNext; if (slow == quick) { break; } } // 无环的话 if (slow != quick ) { return 0; } // p1表示相遇的点, p2表示p1->next //然后把p1->next 置为0 //那么原链表形成了2个相交链表,一个以head为表头,一个以p2为表头 ListNode * p1 = quick; ListNode * p2 = p1->m_pNext; p1->m_pNext = 0; ListNode * firtNode = FirstCommonNode(head,p2); p1->m_pNext = p2; return firtNode; } //给定单链表中某一个节点P,删除该节点(P节点不是最后节点) //方法:首先存放好p中数据,然后把P->next中数据copy到p中,然后把p->next删除。 int DeleteNode(ListNode * p) { if (!p) { return INT_MIN; } int tmp = p->m_nKey; ListNode * tmpNode = p->m_pNext; p->m_nKey = p->m_pNext->m_nKey; p->m_pNext = p->m_pNext->m_pNext; if (tmpNode != 0) { delete tmpNode; tmpNode = 0; } } //给定单链表中某一个非空节点P,在节点P前面插入一个节点 //方法:首先分配一个节点q,将q插在p点之后 //然后将p点数据copy到q节点中,然后再把要插入的数据放到p中 int InsertNode(ListNode * p, int data) { if (!p) { return INT_MIN; } ListNode * tmpNode = new ListNode(); tmpNode->m_nKey = p->m_nKey; tmpNode->m_pNext = p->m_pNext; p->m_pNext = tmpNode; p->m_nKey = data; } int main() { int arr[] = {1, 2, 3}; int brr[] = {4, 5, 6}; int crr[] = {7, 8, 9}; int alen = sizeof(arr)/sizeof(arr[0]); int blen = sizeof(brr)/sizeof(brr[0]); int clen = sizeof(crr)/sizeof(crr[0]); ListNode * head1 = 0; ListNode * head2 = 0; ListNode * head3 = 0; CreateList(head1, arr, alen); CreateList(head2, brr, blen); CreateList(head3, crr, clen); //合并链表1和链表3 head1 = UnionList(head1, head3); //合并链表2和链表3 head2 = UnionList(head2, head3); //打印链表1 dump(head1); //打印链表2 dump(head2); //寻找两个链表的第一个公共节点 ListNode *findNode = FirstCommonNode(head1, head2); printf("第一个公共节,地址为:Ox%x 值为:%d\n", findNode, findNode->m_nKey); findNode = HasLoop(head1); findNode == 0?printf("没有环\n"):printf("有环,换的入口节点值为:%d\n", findNode->m_nKey); return 0; }
相关文章推荐
- 两个单向链表,判断它们是否相交,若相交,找出它们的第一个公共的结点
- 已知有两个链表,判断它们是否相交,若相交求其第一个公共节点
- 转:判断两个单向链表是否相交,并找到两个单向链表的第一个相交节点
- 判断链表是否有环以及环的入口点,两链表是否有公共节点
- 题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。 ②判断两个单向链表是否相交,如果相交则找到交点节点。
- 判断两个单链表是否相交同时找出第一个相交点(单链表是否有环及寻找入口节点)
- 1)两链表的第一个公共结点 2)判断两链表是否相交
- 链表是否存在环及环入口点、两个链表是否相交、相交链表的第一个公共结点
- 判断两个链表是否相交;查找两个链表的第一个公共节点;头插法建链表(补充)
- 链表是否存在环及环入口点、两个链表是否相交、相交链表的第一个公共结点
- 编程之美-编程判断两个链表(可能含环)是否相交以及相交的第一个结点
- 第7题 微软亚院之编程判断俩个链表是否相交 给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交,并找出第一个相交结点。
- 判断链表有环没环及环的入口结点问题 和 判断两个链表是否相交
- 判断两个无环单向链表/有环单向链表是否相交,并返回相交节点
- 链表——判断链表是否有环以及环的入口结点
- 判断两个链表是否相交并找出第一个相交节点
- 两条相交的单向链表,如何求他们的第一个公共节点
- 两链表的第一个公共结点(比较两个链表节点是否相同时比较不了啊,该题尚未完成)
- [LeetCode] 判断两个链表是否有公共节点并返回第一个公共节点
- 判断两链表相交的问题(分有环和无环,以及求第一个相交结点)