编程之美上的一道题。
给出两个单向链表的头指针,比如h1和h2,判断这两个链表是否相交。先假设链表不带环。
首先对于“链表相交”这个概念,要澄清一下,不是单点相交,而是如下这种:
其实也很好理解,相交在平面几何里面的概念是点重合。那么对于链表中某个结点重合,必然next指针也是一样的,于是就是上面这个样子了。
思路:如上分析后就很简单了,如果相交,那么肯定从h1找到尾部(NULL的前一个)和好
找到的尾部是重合的。如果不重合,肯定不相交,是重要条件。
代码如下:
int ll_is_cross(struct Node* a, struct Node* b) { if(a==NULL || b==NULL) { return -1; } while(a->next!=NULL) { a = a->next; } while(b->next!=NULL) { b = b->next; } if(a==b) { return 1; } else { return 0; } }
其他支持代码如下:
#include <iostream> struct Node { struct Node* next; int data; }; int ll_append(struct Node* & root, int data) { if(root==NULL) { root = new Node(); root->next = NULL; root->data = data; return 0; }else { struct Node* ptr = root; while(ptr->next!=NULL) { ptr = ptr->next; } // Append to tail ptr->next = new Node(); if(!ptr->next) { return -1; } ptr->next->data = data; ptr->next->next = NULL; return 0; } } // Merge b to a's tail int ll_merge(struct Node* a, struct Node* b) { if(a==NULL || b==NULL) { return -1; } while(a->next!=NULL) { a = a->next; } a->next = b; } void ll_print(struct Node* root) { while(root!=NULL) { ::std::cout << root->data << " "; root = root->next; } ::std::cout << ::std::endl; } int main() { struct Node* list1 = NULL; struct Node* list2 = NULL; struct Node* list3 = NULL; for(int i=1;i<=4;i++) { ll_append(list1, i); } for(int i=5;i<=8;i++) { ll_append(list2, i); } ll_append(list3, 1); ll_append(list3, 3); ll_merge(list1, list2); ll_merge(list3, list2); ll_print(list1); ll_print(list3); ::std::cout << "list cross: " << ll_is_cross(list1, list2) << ::std::endl; return 0; }
如果现在要求把重复的部分打出来应该怎么做呢?
其实也不复杂,我们设A链表A和B的长度分别是是L(a)和L(b),则让短的哪个链表走 |L(a) - L(b)| 步,然后开始比较两个指针,直到有相等的即可。
代码如下:
void ll_is_cross_and_print(struct Node* heada, struct Node* headb) { struct Node* a = heada; struct Node* b = headb; if(a==NULL || b==NULL) { return ; } int lena = 0; while(a->next!=NULL) { a = a->next; lena++; } int lenb = 0; while(b->next!=NULL) { b = b->next; lenb++; } if(a==b) { // cross, then would print cross part a = heada; b = headb; if(lena<lenb) { int i = 0; while(i<(lenb-lena)) { b = b->next; i++; } }else { int i = 0; while(i<(lena-lenb)) { a = a->next; i++; } } ::std::cout << a->data <<::std::endl; ::std::cout << b->data <<::std::endl; while(a!=NULL && b!=NULL) { if(a==b) { ::std::cout << "Cross part:"; ll_print(a); break; }else { a = a->next; b = b->next; } } return ; } else { // no cross ::std::cout << "No cross part;" << ::std::endl; return ; } }