單鏈表有環求長度及相交問題

單鏈表的節點只有一個指針指向下一個節點,兩個單鏈表相交的話就會致使兩個單鏈表的尾節點是相同的,因此只須要比較尾節點是否相同就能夠知道兩個單鏈表是否相交。可是,這樣是否就徹底沒有問題了呢?

環! 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;
}
相關文章
相關標籤/搜索