判断链表是否相交

1. 判断两个均不含有环的单链表是否相交——编程之美3.6

两个没有环的链表相交于一节点,则在这个节点之后的所有结点都是两个链表所共有的。如果它们相交,则最后一个结点一定是共有的,则只需要判断最后一个结点是否相同即可。时间复杂度为O(len1+len2)。

struct Node
{
	int data;
	Node *next;
};

bool isCross(Node *head1, Node *head2)
{
	Node *p1 = head1, *p2 = head2;
	while (p1->next) p1 = p1->next;
	while (p2->next) p2 = p2->next;
	return p1 == p2;
}

对于相交的第一个结点,则可求出两个链表的长度,然后用长的减去短的得到一个差值 K,然后让长的链表先遍历K个结点,然后两个链表再开始遍历,进行比较,第一个相等的指针为目标节点。

2. 判断链表是否存在环

可以设置两个指针fast和slow,初始均指向头结点,slow每次向前一步,fast每次向前两步;如果链表中有环,则fast先进入环中,而slow后进入环中,两个指针在环中必定相遇;如果fast遍历到尾部为NULL,则无环。

bool isExitsLoop(Node *head)
{
	if (head == NULL) return 0;
	Node *slow = head, *fast = head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
		if (slow == fast) return 1;
	}
	return 0;
}

3. 如果链表为存在环,如何找到环的入口点?

当fast与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
  2s = s + nr
  s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
  a + x = nr
  a + x = (n – 1)r +r = (n-1)r + L - a
  a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点
因而,可以在链表头,相遇点分别设定一个指针,每次各走一步,两个指针必定相遇,且第一个相遇点为环入口点。

Node *findLoopPort(Node *head)
{
	Node *slow = head, *fast = head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
		if (slow == fast) break;
	}

	if (fast || fast->next) return NULL;

	slow = head;
	while (slow != fast)
	{
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

4. 现在也可以解决第1个问题的入口点问题:如果链表不含有环,如何找到第一个不相交的结点?

将问题转化为上一个问题:将第二个链表首尾相连,然后判断第一个链表是否有环,如果有,则它们必然相交,否则不相交。如何找到相交的首个节点呢?其实也就是第一个链表的环的入口节点。

Node *findPort(Node *head1, Node *head2)
{
	Node *tail2 = head2;
	while (tail2->next)
		tail2 = tail2->next;
	tail2->next = head2;//给单链表建环

	Node *temp = findLoopPort(head1);
	tail2->next = NULL;//给单链表解环
	return temp;
}

5. 删除非头结点单链表的指定节点(只给定待删除节点指针)——编程之美3.4

随机给出单链表中一个非头节点或者尾节点,删除该节点,当传入空节点时,返回 。
思路:由于没有头节点,非循环单链表,无法获取目标节点的前一节点,所以只能把它的next节点数据前移,并删除next节点。

void deleteRandomNode(Node *pCur)
{
	assert(pCur != NULL);
	Node *pNext = pCur->next;
	if (pNext != NULL)
	{
		pCur->next = pNext->next;
		pCur->data = pNext->data;
		delete pNext;
	}
}

 

posted @ 2013-08-20 21:43  虫不知  阅读(305)  评论(0编辑  收藏  举报