题目: 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;
}
关于链表的一些基本功能 点击打开链接