環! 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; }