题目:输入两个链表的头节点,判断这两个链表是否存在相交
链表的定义如下:
typedef int Elemtype;
typedef struct ListNode
{
Elemtype data;//值域
ListNode *m_pNext;//指针域
}ListNode,*PListNode;
看到这个题目后大多数的人的第一反应应该就是,判断这两个链表的任意一个节点的指针是否相同,如果有那么这两个链表相交,否则不想交,然后呢用二重for循环来一一查找。显然这是一种笨方法,时间效率极其低下,那么我们来分析如何能够优化该解决方案呢?
首先我们先来分析,两个链表相交能出现哪些情况呢?
第一种:
在第n个节点开始这两条链表的后续重叠。好像两个相爱的人,在相遇了之后,便永不分离。
第二种:
这种相交情况在现实中虽然存在,但是呢,在链表目前的状态下,是无法实现的,因为每一个m_pNext指针只能指向下一个节点,并不能同时指向两个节点,除非我们在单个链表中的节点数据结构定义两个指针,树形链表,这里不做讨论。
第三种:
两条链表只在第n个节点相交,这种情况同上。
所以呢针对第一种情况,我们该怎么优化呢?
首先我们要比较这两个链表中的某任意节点的地址是一样呢。那么我们应该怎么比较呢?不能通过上面提到的穷举发,那么我们就要有一定的法则,我们观察第一种情况的图片可以发现,较长的链表的和较短的链表的 从后到前 长度为短链表的长度的部分是一一对应的,我们通过逆向思维,可以发现,长链表longlen减去短链表shortlen为mylen,我们让长链表先走到第mylen个节点,此时在和较短链表进行比较,此时他们是一一对应的。
调试代码如下:
测试:①输入任意一个为空的链表②输入两个不相交的链表③输入两个相交的链表
#include<assert.h>
#include<iostream>
using namespace std;
typedef int Elemtype;
typedef struct ListNode
{
Elemtype data;//值域
ListNode *m_pNext;//指针域
}ListNode,*PListNode;
ListNode* BuyNode()
{
ListNode* p = (ListNode*)malloc(sizeof(ListNode));
if(NULL == p)
{
printf("buynode is error:\n");
exit(1);
}
memset(p,0,sizeof(ListNode));
return p;
}
void InitList(PListNode &p)
{
p = BuyNode();
p->m_pNext = NULL;
p->data = 0;
}
int GetLength(PListNode &head)//问题出现:不能直接操作head节点
{
int count = 0;
PListNode s = head;
while(s!=NULL)
{
count+=1;
s=s->m_pNext;
}
return count;
}
void InsertList(PListNode &p,Elemtype x,int pos)
{
if(pos<1 || pos>GetLength(p)+1)
{
printf("input pos is error:\n");
exit(1);
}
PListNode s = p;//头节点s
if(pos == 1)
{
p->data = x;
p->m_pNext = NULL;
}
else
{
while(pos-2)
{
s = s->m_pNext;
--pos;
}//s指向前驱
PListNode r =s->m_pNext;
PListNode q = BuyNode();
q->data = x;
s->m_pNext = q;
q->m_pNext = r;
}
}
void Show_List(PListNode &head)
{
PListNode s =head;
while(s != NULL)
{
printf("%d ",s->data);
s = s->m_pNext;
}
printf("\n");
}
PListNode FirstNode(PListNode &phead,PListNode &qhead)
{
assert(phead != NULL && qhead != NULL);
int len1 = GetLength(phead);
int len2 = GetLength(qhead);
PListNode plong = phead;
PListNode pshort = qhead;
int my_len = len1-len2;
if(len2>len1)
{
plong = qhead;
pshort = phead;
my_len = len2-len1;//my_len鐩稿樊鐨勯暱搴?
}
for(int i= 0;i < my_len;i++)
{
plong = plong->m_pNext;
}
while(plong != NULL && pshort != NULL && plong != pshort)
{
plong = plong->m_pNext;
pshort = pshort->m_pNext;
}
PListNode FirstNode = plong;
return FirstNode;
}
void main()
{
PListNode phead;//第一个链表
InitList(phead);
for(int i=1;i<8;++i)
{
InsertList(phead,i+10,i);
}
Show_List(phead);
PListNode qhead;//第二个链表
InitList(qhead);
for(int i=1;i<5;++i)
{
InsertList(qhead,i+10,i);
}
Show_List(qhead);
/*
//使两个链表相交的操作
PListNode r = qhead;
while(r->m_pNext != NULL)
{
r = r->m_pNext;
}
PListNode s = phead;
for(int i=1;i<3;++i)
{
s = s->m_pNext;
}
r->m_pNext = s;
Show_List(qhead);
*/
PListNode p = FirstNode(phead,qhead);
if(p != NULL)
{
printf("%d \n",p->data);
}
else
printf("没有相交:\n");
}
调试①:终止。
调试②:
调试③: