题目:假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,可共享相同的后缀存储空间,例如,“loading”,“being”的存储映像如下图所示。
设str1和str2分别指向两个单词所在单链表的头结点,链表结点结构为
data | next |
---|
请设计一个时间上尽可能高效的算法,找出由str1和str2所指向两个链表共同后缀的起始位置(如图中字符i所在结点的位置p)
关键字:2个带头结点单链表+查找共同后缀
思路
关注:本题确定给出str1和str2是含有共同后缀的,不需要对是否含有共同后缀进行讨论,直接查找共同后缀的首元素即可
查找思路:因为确定两个单链表含有相同后缀,
所以首先查找“疑似共同后缀首元素”,
之后检验其是否为真正的共同后缀首元素(检验方法:本题的结构体是单链表,采用双指针法。
用指针p,q分别扫描str1,str2,当p、q指向同一个地址时即找到共同后缀的起始位置)
算法的基本设计思想:
1.分别求出str1和str2的链表长度m和n
2.将两个链表以表尾对齐:令指针p、q分别指向str1和str2的头结点
若m>=n,则指针p先走m-n个位置,使p指向链表中的第m-n+1个结点;
若m<n,则使q先走n-m个位置,使q指向链表中的第n-m+1个结点;
3.同时向后遍历,当p和q指向元素的地址相同时停止(因为共同后缀共享地址),即为共同后缀的起始位置,返回这个指针,算法结束
typedef struct Node{
char data;
struct Node*next;
}SNode;
int listlen(SNode*head){//定义一个求链表长度的函数
int len=0;
while(head->next!=NULL){
len++;
head=head->next;
}
return len;
}
SNode*find_addr(SNode*str1,SNode *str2){
int m,n;
SNode*p,*q;
m=listlen(str1);
n=listlen(str2);
for(p=str1;m>n;m--)
p=p->next;
for(q=str;m<n;n--)
q=q->next;
while(p->next!=NULL&&p->next!=q->next)//将指针p和q同时向后遍历
p=p->next;
q=q->next;
}
return p->next;//返回共同后缀的起始地址
}