单链表面试题---判断两个链表是否相交( 不带环 )和( 可能带环 ) , 若相交 , 求交点

题目:  1 .判断两个链表是否相交 , 假设两个链表不带环 , 若相交 , 求出交点

          2 .判断两个链表是否相交 , 假设两个链表可能带环 , 若相交 , 求交点

假设两个链表不带环  解法 : 方法1. 遍历两个链表 , 记录两个链表的长度 , ①当两个链表的长度不相等 , 则长链表先走len_max - len_min长度 , 然后两个链表同时前进 , 并且比较 , 当两个链表相等时 , 记录当前位置 , 并且返回该节点 . ②当两个链表的长度相等 , 则两个链表同时前进 , 并且比较 , 当两个链表相等时 , 记录当前位置 , 并且返回该节点位置 . 当两个链表任意一个为空时 , 比较结束 , 则没有交点 , 返回NULL .

                                           方法2. 将其中任意一个链表首尾相连 , 判断另一个链表是否存在环 , 若存在 , 则该链表环的入口点就为两个链表相交的点 . 

假设两个链表可能带环   解法  :  1.  判断链表是否带环 , 方法 : 用两个指针( fast , slow ) , 初始都指向链表头结点 , fast每次前进两步 , slow每次前进一步 , 如果链表存在环 , 那么必定会相遇 . 如图所示 , 当fast与slow相遇时,slow还没走完链表,而fast已经在环内循环了n圈了,假设slow在相遇前走了s步,则fast走了2s步,设环长为r,有2s=s+nr,即s=nr.由上图可知a+x=s, x+y=r,而我们的目标是找到a的位置。设上图那个拱起的曲线的长度为y,有a+x=s=nr=(n-1)r+r=(n-1)r+y+x ,则a=(n-1)r+y . 这个公式告诉我们,从链表头和相遇点分别设一个指针,每次各走一步,这两个指针必定相遇,且相遇的第一个点为环入口点 ,

                                         

                                                 2.  判断是否会相交 , pos1代表链表一的入口点 , pos2代表链表二的入口点 , 用两个指针( fast  , slow ) , 开始两个指针都指向pos2 , fast每次前进2步 , slow , 每次前进1步 , 若在fast 和 slow相遇之前有fast ==  pos1或者fast-  > next ==  pos1 , 则说明两个链表相交 , 否则不相交 . 若两链表相交 , 将这个当做两个链表的终止节点 , 然后使用不带环解法中的方法二 , 就可以找出两链表相交的第一节点 . 

Linklist . h  头文件

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <windows.h>

//定义元素类型
typedef int DataType;
//链表的定义
typedef struct Node
{
	DataType data;			//存放数据
	struct Node* next;		//定义一个struct Node类型的指针记录下一个节点的地址
}Node, *pNode, List, *pList;

//初始化链表
void InitLinkList(pList* pplist);
//尾插
void PushBack(pList* pplist, DataType d);
//查找
pNode Find(pList plist, DataType d);
//链表长度
int GetListLength(pList plist);
//判断单链表是否带环,求出带环的入口点
pNode JudgeLinkLoop(pList plist);
//判断两个链表是否相交,若相交,求交点。(假设不带环)
pNode SeekLinkIntersectNodeWayOne(pList plist, pList qlist);
pNode SeekLinkIntersectNodeWayTwo(pList plist, pList qlist);
//判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
pNode JudgeLoopLinkIntersect(pList plist, pList qlist);    //判断是否相交
pNode SeekLoopLinkIntersectNode(pList plist, pList qlist); //求出两个链表相遇的第一个节点

#endif __LINKLIST_H__

Linklist . c  功能文件

#include "Linklist.h"

//链表的初始化
void InitLinkList(pList* pplist)
{
	*pplist = NULL;
}
//申请节点
pNode BuyNode(DataType d)
{
	pNode L = (Node *)malloc(sizeof(Node));
	if (L == NULL)
	{
		perror("Buy Node");
		exit(FILENAME_MAX);
	}
	L->data = d;
	L->next = NULL;
	return L;
}
//尾插
void PushBack(pList* pplist, DataType d)
{
	pNode p;
	assert(pplist);				//断言,链表不为空
	p = *pplist;
	//当链表为空,不需要遍历链表,需特殊处理
	if (p == NULL)
	{
		*(pplist) = BuyNode(d);
	}
	else
	{
		//遍历链表,找到尾节点
		while (p->next != NULL)
		{
			p = p->next;
		}
		p->next = BuyNode(d);
	}
}
//查找
pNode Find(pList plist, DataType d)
{
	if (plist == NULL)
        {
            return NULL;
        }               
	while (plist)
	{
		if (plist->data == d)
		{
			return plist;
		}
		plist = plist->next;
	}
	return NULL;
}
//链表长度
int GetListLength(pList plist)
{
	int count = 0;
	if (plist == NULL)
	{
		return 0;
	}
	else
	{
		while (plist)
		{
			count++;
			plist = plist->next;
		}
		return count;
	}
}
//判断单链表是否带环,求出带环链表的入口点
pNode JudgeLinkLoop(pList plist)
{
	pNode fast = NULL;
	pNode slow = NULL;
	pNode head = NULL;
        if (plist == NULL)
        {
            return NULL;
        }
	slow = plist->next;
	fast = slow->next;
	while (fast && fast->next)
	{
		if (slow == fast)
		{
			head = plist;
			while (head->data != slow->data)
			{
				head = head->next;
				slow = slow->next;
			}
			return head;
		}
		slow = slow->next;
		fast = fast->next->next;
	}
	return NULL;
}
//判断两个链表是否相交,若相交,求交点。(假设不带环)
pNode SeekLinkIntersectNodeWayOne(pList plist, pList qlist)
{
	int num1 = 0;
	int num2 = 0;
	pNode ret = NULL;
        if (plist == NULL && qlist == NULL)
        {
            return NULL;
        }
	num1 = GetListLength(plist);
	num2 = GetListLength(qlist);
	if (num1 != 0 && num2 != 0)
	{
		if (num1 >= num2)
		{
			ret = plist;
			num1 = num1 - num2;
			while (num1--)
			{
				ret = ret->next;
			}
			while (ret != qlist)
			{
				ret = ret->next;
				qlist = qlist->next;
			}
			return ret;
		}
		else
		{
			ret = qlist;
			num2 = num2 - num1;
			while (num2--)
			{
				ret = ret->next;
			}
			while (ret != plist)
			{
				ret = ret->next;
				plist = plist->next;
			}
			return ret;
		}
	}
	return NULL;
}
pNode SeekLinkIntersectNodeWayTwo(pList plist, pList qlist)
{
	pNode tmp = NULL;
	pNode head = NULL;
	pNode tail = NULL;
	int count = 0;
	if (plist == NULL && qlist == NULL)
        {
            return NULL;
        }
	tail = plist;
	head = plist;
	while (tail && tail->next)  //找到链表plist的尾节点
	{
		tail = tail->next;
	}
	tail->next = head;          //将链表首尾相连
	tmp = JudgeLinkLoop(qlist);
	return tmp;
}

//判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
pNode JudgeLoopLinkIntersect(pList plist, pList qlist)
{
	pNode pos1 = NULL;
	pNode pos2 = NULL;
	pNode fast = NULL;
	pNode slow = NULL;
	assert(plist && qlist);        //断言,链表不为空
	pos1 = JudgeLinkLoop(plist);   //plist的入口点
	pos2 = JudgeLinkLoop(qlist);   //qlist的入口点
	if (pos1 && pos2)
	{
		fast = pos2;
		slow = pos2;
		//判断是否相交
		do
		{
			if ((fast == pos1) || (fast->next == pos1))
			{
				break;
			}
			fast = fast->next->next;
			slow = slow->next;
		} while (fast != slow); //在不相等的状况下,循环刚好遍历一遍环
		//不相交返回空
		if ((fast != pos1) && (fast->next != pos1))
		{
			return NULL;
		}
		//返回相交点
		else
		{
			return pos1;
		}
	}
	else
	{
		return NULL;
	}
}
pNode SeekLoopLinkIntersectNode(pList plist, pList qlist)
{
	pNode fast = NULL;
	pNode pos = NULL;
	pNode pos1 = NULL;
	pNode pos2 = NULL;
	pNode slow = NULL;
	int num1 = 0;
	int num2 = 0;
	assert(plist && qlist);     //断言,链表不为空
	pos = JudgeLoopLinkIntersect(plist, qlist);
	pos1 = plist;
	pos2 = qlist;
	if (pos != NULL)
	{
		while (pos1 != pos)
		{
			num1++;
			pos1 = pos1->next;
		}
		while (pos2 != pos)
		{
			num2++;
			pos2 = pos2->next;
		}
		if (num1 >= num2)
		{
			pos1 = plist;
			num1 = num1 - num2;
			while (num1--)
			{
				pos1 = pos1->next;
			}
			while (pos1 != qlist)
			{
				pos1 = pos1->next;
				qlist = qlist->next;
			}
			return pos1;
		}
		else
		{
			pos2 = qlist;
			num2 = num2 - num1;
			while (num2--)
			{
				pos2 = pos2->next;
			}
			while (pos2 != plist)
			{
				pos2 = pos2->next;
				plist = plist->next;
			}
			return pos2;
		}
	}
	else
	{
		return NULL;
	}
}

test . c 测试文件

#include "Linklist.h"
void teatJudgeLinkIntersect()
{
	pNode cmd = NULL;
	pList plist;
	pList qlist;
	pNode ret = NULL;
	pNode tail = NULL;
	InitLinkList(&plist);
	InitLinkList(&qlist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&qlist, 8);
	PushBack(&qlist, 9);
	PushBack(&qlist, 10);
	ret = Find(plist, 3);
	tail = qlist;
	while (tail && tail->next)
	{
		tail = tail->next;
	}
	tail->next = ret;
//      cmd = SeekLinkIntersectNodeWayOne(plist, qlist);
	cmd = SeekLinkIntersectNodeWayTwo(plist, qlist);
	if (cmd != NULL)
	{
		printf("两个链表相交!交点为:%d\n", cmd->data);
	}
	else
	{
		printf("两个链表不相交!\n");
	}
}
void testJudgeLoopLinkIntersect()
{
	pList plist;
	pList qlist;
	pNode cmd = NULL;
	pNode ret = NULL;
	pNode tail = NULL;
	pNode cur = NULL;
	pNode newNode = NULL;
	InitLinkList(&plist);
	InitLinkList(&qlist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	PushBack(&qlist, 8);
	PushBack(&qlist, 9);
	PushBack(&qlist, 10);
	ret = Find(plist, 3);
	tail = plist;
	while (tail && tail->next)
	{
		tail = tail->next;
	}
	tail->next = ret;
	cur = qlist;
	while (cur && cur->next)
	{
		cur = cur->next;
	}
	cur->next = ret;
	cmd = JudgeLoopLinkIntersect(plist, qlist);
	if (cmd != NULL)
	{
		newNode = SeekLoopLinkIntersectNode(plist, qlist);
		printf("两个链表相交!交点为:%d\n", newNode->data);
	}
	else
	{
		printf("两个链表不相交!\n");
	}
}
int main()
{
//	teatJudgeLinkIntersect();
	testJudgeLoopLinkIntersect();
	system("pause");
	return 0;
}

关于链表的一些基本功能 点击打开链接


猜你喜欢

转载自blog.csdn.net/ds19980228/article/details/80940128