知识点导航:【数据结构】线性表——顺序存储
知识点导航:【数据结构】线性表——链式存储
[王道数据结构]习题导航: p a g e 41.23 page41.23 page41.23
本节为链表相关的习题 |
题目描述:
思路:双指针
思路分析:
其实,对于这道题来说,思路很简单,在我们已知了公共后缀链之后,要得到公共后缀的首位置,由于是后缀相同,于是我们 将两个链表的表尾对齐之后,依次扫描,直到指向两个链表的指针 p , q p,q p,q指向同一位置时,即为公共元素起始地址
step:
图解:
于是,我们可以将完整的实现拆分为以下几个步骤:
①初始化链表
链表的初始化:
代码实现:
bool InitList(LinkList& L) {
L = (LNode *)malloc(sizeof(LNode)); //开辟空间存放头结点
LNode* p = L;
int x;
while (cin >> x) {
LNode* s0 = (LNode*)malloc(sizeof(LNode));
s0->data = x;
p->next = s0;
p = s0;
if (cin.get() == '\n')
break;
}
//不要忘了尾结点连NULL
p->next = NULL;
return true;
}
②求链表长度
循环遍历即可
int length(LinkList& L) {
int count = 0;
LNode* p = L;
while (p->next != NULL) {
p = p->next;
count++;
}
return count;
}
③链表尾结点对齐
要让尾结点对齐,我们需要先传入指向两个链表的头结点的指针 p , q p,q p,q
在函数中修改指针:
由于要对指针本身进行修改,我们则需要传入指针的地址,也就是指针的指针 ∗ ∗ p 和 ∗ ∗ q **p和**q ∗∗p和∗∗q,在函数内部使用时,则需要对二级指针进行解引用,才为指针 p , q p,q p,q,即 ∗ p = ( ∗ p ) − > n e x t *p=(*p)->next ∗p=(∗p)−>next
代码实现:
void alignment(LinkList& L1, LinkList& L2,LNode **p,LNode **q) {
int l1 = length(L1);
int l2 = length(L2);
int start;
int count = 0;
//较长链表的指针位置
if (l1 >= l2)
{
start = l1 - l2 ;
while (count != start) {
*p = (* p)->next;
count++;
}
}
else
{
start = l2 - l1 ;
while (count != start) {
*q = (*q)->next;
count++;
}
}
}
④求解公共后缀的首元素地址:
在得到对齐后的指针 p , q p,q p,q后,我们不断移动两个指针,直到相等,若最后 p − > n e x t p->next p−>next为空,则表示无公共后缀
代码实现:
LNode* Findindex(LinkList& L1, LinkList& L2) {
LNode* p = L1; LNode* q = L2;
alignment(L1, L2, &p, &q);
//同时移动
while (p->next != NULL && p->next != q->next) {
p = p->next;
q = q->next;
}
return p->next;
}
⑤构造共享后缀链:
对于两个单独存在的链表,我们如何将他们的公共后缀存储在同一片内存空间呢?
step:
首先,我们仍需要先将两个链表对齐;
然后我们开始同时移动两个指针 p , q p,q p,q,当指针指向的下一个结点 p − > n e x t p->next p−>next不为 N U L L NULL NULL时:
①如果两个单链表中的下一个结点对应的值不相同,则指针 p , q p,q p,q继续向后移动;
②如果两个单链表中的下一个结点对应的值相同,则复制两个 p , q p,q p,q的辅助指针 a 1 , a 2 a1,a2 a1,a2向后深搜,直到下一个结点 a 1 − > n e x t a1->next a1−>next为 N U L L NULL NULL 或 两个辅助指针对应的下一个结点的值不相同:
图解算法:
代码实现:
void Storage(LinkList& L1, LinkList& L2) {
LNode* p = L1; LNode* q = L2;
alignment(L1, L2, &p, &q);
//存储公共后缀链
while (p->next != NULL ) {
//1.下一个元素相同
if (p->next->data == q->next->data) { //如果数据相同
LNode* a1 = p->next;
LNode* a2 = q->next;
while (a1->next!=NULL && a1->next->data==a2->next->data) { //不断比较后续结点是否相同
a1 = a1->next;
a2 = a2->next;
}
//1.有公共后缀
if (a1->next == NULL) {
p->next = q->next; //共享后缀,结束
break;
}
//2.暂时没有公共后缀 :也就是a1->next!=a2->next
else {
p = a1->next;
q = a2->next; //以新起点开始,继续往下比较
continue;
}
}
//2.下一个元素不同
else{
p = p->next;
q = q->next; //向后移动,继续找
}
}
}
完整代码实现:
#include
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
}LNode,*LinkList;
//初始化
bool InitList(LinkList& L) {
L = (LNode *)malloc(sizeof(LNode)); //开辟空间存放头结点
LNode* p = L;
int x;
while (cin >> x) {
LNode* s0 = (LNode*)malloc(sizeof(LNode));
s0->data = x;
p->next = s0;
p = s0;
if (cin.get() == '\n')
break;
}
//不要忘了尾结点连NULL
p->next = NULL;
return true;
}
//求长度
int length(LinkList& L) {
int count = 0;
LNode* p = L;
while (p->next != NULL) {
p = p->next;
count++;
}
return count;
}
//1.对齐
void alignment(LinkList& L1, LinkList& L2,LNode **p,LNode **q) {
int l1 = length(L1);
int l2 = length(L2);
int start;
int count = 0;
//较长链表的指针位置
if (l1 >= l2)
{
start = l1 - l2 ;
while (count != start) {
*p = (* p)->next;
count++;
}
}
else
{
start = l2 - l1 ;
while (count != start) {
*q = (*q)->next;
count++;
}
}
}
//2.共享后缀链
void Storage(LinkList& L1, LinkList& L2) {
LNode* p = L1; LNode* q = L2;
alignment(L1, L2, &p, &q);
//存储公共后缀链
while (p->next != NULL ) {
//1.下一个元素相同
if (p->next->data == q->next->data) { //如果数据相同
LNode* a1 = p->next;
LNode* a2 = q->next;
while (a1->next!=NULL && a1->next->data==a2->next->data) { //不断比较后续结点是否相同
a1 = a1->next;
a2 = a2->next;
}
//1.有公共后缀
if (a1->next == NULL) {
p->next = q->next; //共享后缀,结束
break;
}
//2.暂时没有公共后缀 :也就是a1->next!=a2->next
else {
p = a1->next;
q = a2->next; //以新起点开始,继续往下比较
continue;
}
}
//2.下一个元素不同
else{
p = p->next;
q = q->next; //向后移动,继续找
}
}
}
//3.查找位置
LNode* Findindex(LinkList& L1, LinkList& L2) {
LNode* p = L1; LNode* q = L2;
alignment(L1, L2, &p, &q);
//同时移动
while (p->next != NULL && p->next != q->next) {
p = p->next;
q = q->next;
}
return p->next;
}
int main() {
LinkList L1;
LinkList L2;
//初始化
cout << "请输入链表L1的元素:" << endl;
InitList(L1);
cout << "请输入链表L2的元素:" << endl;
InitList(L2);
//合成为公共后缀链
Storage(L1, L2);
//查找存储链的公共后缀的首地址
if (Findindex(L1,L2))
{
cout << "公共后缀的首地址为:" << Findindex(L1, L2) << endl;
cout << "公共后缀的首元素为:" << Findindex(L1, L2)->data << endl;
}
else
cout << "不存在公共后缀" << endl;
system("pause");
return 0;
}
输出结果: