环! node
其实否则,单链表有可能没有尾节点!为何?由于有可能存在环!若是存在环的话上面那个办法就行不通了!考虑到由于环的存在,原来单链表的尾节点消失了,既然由于环没有尾节点了,那咱们就创造一个尾节点! ios
假设两个单链表分别为A和B,第一步,遍历A,使用两个指针,一个指针每一步移动一个节点,另外一个指针每一步移动两个节点(固然这里的一个节点和两 个节点能够替换为别的数目,只要保证两个数的最大公约数为1就能够了,由于这个能够保证两个指针在环中必定会相遇)。使用两个指针遍历链表A,若是某一步 两个指针相等,那么说明存在环,就将这一点做为A的尾节点,若是不存在环,咱们最终也能得到A的尾节点。第二步,遍历链表B,并将每个节点和A的尾节点 相比较,若是存在相同的节点,那么说明两个链表相交,不然不相交。使用这种方法咱们最终能在O(n+m)(n为A的长度,m为B的长度)的时间复杂度内解 决问题。 spa
环的长度怎么求? 指针
若是知道链表A有环,那么怎么求出A的环的长度呢?这个问题其实很是简单!上文中已经描述了找到链表A的环中的一个节点,也就是那个尾节点,只要绕环一周即可以计算出环的 长度。 code
环的第一个节点? 同步
若是链表有环,怎么求环的第一个节点呢?我在查阅资料的时候发现有这样一个定理:对于有环的单链表A,使用一个每次走一个节点的指针P和一个每次走 两个节点的指针K遍历链表A,当指针P和K第一次碰撞时,此时用一个每次走一个节点的指针H从单链表头开始遍历,当指针P和H相遇时必定位于环的第一个节 点!使用数学方法能够很容易来证实这个定理。设链表的节点为o1,o2,o3,……,oN,i1,i2,……,iK,……,iM其中o1是链表的第一个节 点,oN是环的第一个节点,iK是指针P和K发生碰撞的节点(指针P和K发生碰撞的节点是惟一的),iM的next指针指向oN。当指针P和K第一次相遇 时,此时指针P走过了N+K个节点,而指针K走过了2N+2K个节点,能够获得这样一个等式:N+K = N+((N+2K) mod (M+1)),化简可得:0 = (N+K) mod (M+1)!这个化简后的等式说明,指针P走过N个节点会处于oN节点,而指针H开始指向链表头,它走过N个节点也会位于oN节点,虽然不知到N到底是多 少,可是指针P和H同步走必定会相交于oN,并且相交的第一个位置就是oN。 数学
链表的长度怎么求? io
有了上一段的分析,链表的长度就容易获得了!有环的链表,其长度能够分为两部分来求,一部分是环外,一部是环!若是将无环链表看做是环长度为0的链 表,则能够获得一个统一的求解链表长度的代码,见行93到125,其中,行99到106计算获得iK,行107到115计算环的长度,行116到122计 算环外节点数目。 class
两个单链表的交点怎么求? 效率
若是单链表不存在环,求解交点有两种比较好的方法,第一种方法是将链表尾节点指向其中一个链表的头节点,这样求交点的问题就转换成了求环的第一个节 点问题,第二种方法效率更高一点,首先求出链表A和B的长度LA和LB,假设LA大于LB,将每次移动一个节点的指针PA指向链表A的第LA-LB+1个 节点,将每次移动一个节点的指针PB指向链表B的第一个节点,而后同步移动指针PA和PB,两个指针相同时所指向的节点即是A和B的交点。若是单链表存在 环的话,求解交点就麻烦一点,这里提一个比较简单的办法,对于链表A/B,取环上的第一个节点,将该节点指向链表B/A的头节点,这样获得一个新的有环链 表,分别求解环的第一个节点,能够获得两个节点,若是两个节点相同,说明链表A和B的交点在环外,不然这两个链表在环外没有交点,这两个节点分别是链表A 和B在环上的第一个节点!
下面贴上相关代码!
#include <iostream> using namespace std; struct list { int value; struct list *next; }; struct list *insert(struct list *head, int v) { if (head) { head->next = insert(head->next, v); } else { head = new struct list; head->value = v; head->next = 0; } return head; } void set_next_node(struct list *node, struct list *next) { if (node) { node->next = next; } } struct list *find(struct list *head, size_t idx) { while (idx-- && head && head->next) { head = head->next; } return head; } struct list *first_node(struct list *head1, struct list *head2) { struct list *tail1, *next1 = 0; struct list *cursor1 = head1, *cursor2 = head1; do { if (cursor2) { cursor2 = cursor2->next; if (cursor2) cursor2 = cursor2->next; } tail1 = cursor1; next1 = cursor1->next; cursor1 = cursor1->next; } while (cursor1 != cursor2); cursor2 = head1; do { tail1 = cursor1; next1 = cursor1->next; cursor2 = cursor2->next; if (cursor1) cursor1 = cursor1->next; } while (cursor1 != cursor2); if (cursor1) { tail1 = cursor1; next1 = cursor1->next; } tail1->next = head2; cursor1 = head1, cursor2 = head1; do { if (cursor2) { cursor2 = cursor2->next; if (cursor2) cursor2 = cursor2->next; } cursor1 = cursor1->next; } while (cursor1 != cursor2); do { if (cursor2) { cursor2 = cursor2->next->next; } if (cursor1) { cursor1 = cursor1->next; } } while (cursor1 != cursor2); cursor2 = head1; do { cursor2 = cursor2->next; if (cursor1) cursor1 = cursor1->next; } while (cursor1 != cursor2); tail1->next = next1; return cursor1; } size_t length(struct list *head) { size_t l = 0; if (head) { struct list *cursor1 = head; struct list *cursor2 = head; do { if (cursor2) { cursor2 = cursor2->next; if (cursor2) cursor2 = cursor2->next; } cursor1 = cursor1->next; } while (cursor1 != cursor2); do { if (cursor2) { cursor2 = cursor2->next->next; } if (cursor1) { l++; cursor1 = cursor1->next; } } while (cursor1 != cursor2); cursor2 = head; do { cursor2 = cursor2->next; if (cursor1) cursor1 = cursor1->next; l++; } while (cursor1 != cursor2); } return l; } void print_length(struct list *head, size_t l) { cout << "list: "; while (head && l--) { cout << head->value; if (head->next) { if (l) cout << "->"; else cout << "->[" << head->next->value <<"]"; } head = head->next; } cout << endl; } void print(struct list *head) { print_length(head, length(head)); } int main() { struct list *head1 = 0; struct list *head2 = 0; head1 = insert(head1, 0); head1 = insert(head1, 1); head1 = insert(head1, 2); head1 = insert(head1, 3); head1 = insert(head1, 4); head1 = insert(head1, 5); head1 = insert(head1, 6); head1 = insert(head1, 7); head1 = insert(head1, 8); head1 = insert(head1, 9); head2 = insert(head2, 10); head2 = insert(head2, 11); head2 = insert(head2, 12); head2 = insert(head2, 13); set_next_node(find(head1, -1), find(head1, 4)); set_next_node(find(head2, -1), find(head1, 6)); print(head1); print(head2); cout << length(head1) << endl; cout << length(head2) << endl; cout << "node: " << first_node(head1, head2)->value << endl; cout << "node: " << first_node(head2, head1)->value << endl; return 0; }