判断链表是否相交(无环版)

编程之美上的一道题。

给出两个单向链表的头指针,比如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 ;
	}
}

Leave a Reply

Your email address will not be published.