## 问题描述
> 给定两个单链表,编写算法找出两个链表的共同结点
## 算法思想
> 我们从[单链表的定义](http://blog.csdn.net/u013595419/article/details/50481785#t0)中可以发现每一个结点只有一个next域,那么从第一个公共结点开始,后面所有的结点都应该是重合的,形状应该类似与倒Y型(“`>-`”)。既然如此,那么对两条单链表同时开始遍历,只要它们的指针同时指向同一个结点(即:两指针相等)时不就找到公共结点了吗?
但在实现的时候,应该注意到,两张链表在等长的情况下,同时开始遍历,指针必然可以同时指向公共结点;可是如果不等长的话,同时遍历是无法同时指向公共结点的。
这里总结下思想核心
> - 分别求出两条单链表的长度len1和len2以及长度之差len;
> - 让LongPoint指针指向长度较长的单链表,让ShortPoint指针指向长度较短的单链表;
> - 对齐两条单链表的表尾,让长链表先遍历 len个结点;
> - 长短单链表同时开始遍历,直到指针LongPoint与指针ShortPoint指向同一个结点(相等)时为止。
## 算法描述
~~~
LNode* FindCommon(LNode* head1, LNode* head2)
{
int len1=ListLength(head1);//求链表1的长度
int len2=ListLength(head2);//求链表2的长度
int len; //长短单链表长度差
LNode *LongPoint; //指向长链表
LNode *ShortPoint; //指向短炼表
//判断长短链表
if(len1>len2){
len=len1-len2;
LongPoint=head1->next;
ShortPoint=head2->next;
}else{
len=len2-len1;
LongPoint=head2->next;
ShortPoint=head1->next;
}
//长链表先遍历长短链表长度差个结点
while(len--){
LongPoint=LongPoint->next;
}
//长短链表同时开始遍历
while(LongPoint!=NULL){
if(LongPoint==ShortPoint){
return LongPoint;
}
else{
LongPoint=LongPoint->next;
ShortPoint=ShortPoint->next;
}
}
return NULL;
}
~~~
具体代码见附件。
## 附件
~~~
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
LinkList CreatList(LNode*);
LNode* FindCommon(LNode*,LNode*);
int ListLength(LNode*);
void Print(LNode*);
int main(int argc, char* argv[])
{
LNode *head1;
head1=(LNode*)malloc(sizeof(LNode));
head1->next=NULL;
head1=CreatList(head1);
printf("Head1: ");
Print(head1);
int i=4;
LNode *p=head1;
while(i--){
p=p->next;
}
LNode *head2;
head2=(LNode*)malloc(sizeof(LNode));
head2=CreatList(head2);
LNode *r=head2->next;
while(r->next){
r=r->next;
}
r->next=p;
printf("head2: ");
Print(head2);
LNode *head;
head=(LNode*)malloc(sizeof(LNode));
head->next=NULL;
head->next=FindCommon(head1, head2);
printf("head: ");
Print(head);
return 0;
}
//尾插法建立单链表
LinkList CreatList(LNode *head)
{
LNode *r=head;
LNode *L;
ElemType x;
scanf("%d",&x);
while(x!=999){
L=(LNode*)malloc(sizeof(LNode));
L->data=x;
r->next=L;
r=L;
scanf("%d",&x);
}
r->next=NULL;
return head;
}
//寻找公共结点
LNode* FindCommon(LNode* head1, LNode* head2)
{
int len1=ListLength(head1);
int len2=ListLength(head2);
int len;
LNode *LongPoint;
LNode *ShortPoint;
if(len1>len2){
len=len1-len2;
LongPoint=head1->next;
ShortPoint=head2->next;
}else{
len=len2-len1;
LongPoint=head2->next;
ShortPoint=head1->next;
}
while(len--){
LongPoint=LongPoint->next;
}
while(LongPoint!=NULL){
if(LongPoint==ShortPoint){
return LongPoint;
}
else{
LongPoint=LongPoint->next;
ShortPoint=ShortPoint->next;
}
}
return NULL;
}
//求单链表长度
int ListLength(LNode *head)
{
LNode *p=head;
int count=0;
while(p){
++count;
p=p->next;
}
return count;
}
//打印全部结点
void Print(LNode *head)
{
LNode *p=head->next;
while(p){
printf("%4d",p->data);
p=p->next;
}
printf("\n");
}
~~~
注:
本源代码的主函数部分中,首先创建了单链表1,然后遍历单链表1四个结点,接着让单表2的尾结点的next域指向单链表1的第四个结点,从而形成两条具有公共结点的单链表。
故此代码中最大的Bug就是因为此单链表都是自己创建的,所以公共结点在哪儿一开始就已经知道了。然后睁着眼睛说了半天瞎话……
- 前言
- 绪论
- 第1章线性表
- 第1章第1节 线性表的顺序表示
- 第1章第1节练习题1 删除最小值
- 第1章第1节练习题2 逆置顺序表
- 第1章第1节练习题3 删除指定元素
- 第1章第1节练习题4 有序表删除指定区间值
- 第1章第1节练习题5 无序表删除指定区间值
- 第1章第1节练习题6 删除重复值
- 第1章第1节练习题7 顺序表的归并
- 第1章第1节练习题8 顺序表循环移位
- 第1章第1节练习题9 查找指定值
- 第1章第1节练习题10 查找中位数
- 第1章第2节 线性表的链式表示(1)
- 第1章第2节 线性表的链式表示(2)
- 第1章第2节 线性表的链式表示(3)
- 第1章第2节练习题1 递归删除指定结点
- 第1章第2节练习题2 非递归删除指定结点
- 第1章第2节练习题3 删除最小值结点
- 第1章第2节练习题4 删除指定区间结点
- 第1章第2节练习题5 删除重复结点
- 第1章第2节练习题6 反向输出
- 第1章第2节练习题7 递减输出
- 第1章第2节练习题8 奇偶拆分单链表
- 第1章第2节练习题9 查找公共结点
- 第1章第2节练习题10 查找指定倒数结点
- 第1章第2节练习题11 就地逆置单链表
- 第1章第2节练习题12 单链表之插入排序
- 第1章第2节练习题13 单链表之选择排序
- 第1章第2节练习题14 判断子序列
- 第1章第2节练习题15 拆分并逆序单链表
- 第1章第2节练习题16 归并并逆序单链表
- 第1章第2节练习题17 使用相同值结形成新单链表
- 第1章第2节练习题18 求两个单链表的交集
- 第1章第2节练习题19 判断循环双链表对称
- 第1章第2节练习题20 连接两个循环单链表
- 第1章第2节练习题21 输出并删除最小值结点
- 第1章第2节练习题22 按结点访问频度排序
- 第1章第3节 线性表的比较
- 第2章受限的线性表
- 第2章第1节 栈
- 第2章第1节练习题1 判断栈的操作次序是否合法
- 第2章第1节练习题2 判断是否中心对称
- 第2章第2节 队列
- 第2章第1节练习题3 共享栈的基本操作
- 第2章第2节练习题1 逆置队列
- 第2章第2节练习题2 使用栈模拟队列操作
- 第2章第2节练习题3 使用队列模拟渡口管理
- 第2章第3节 串
- 第2章第3节练习题1 串的模式匹配(Basic)
- 第2章第3节练习题2 串的模式匹配(KMP)