前篇:
(8)分两个过程,先从la中删除一部分,然后将删除的部分插入到链表中。这里要考虑到如果i和j以及截取的长度不在链表的范围内,就要进行提示。
答案:
//第8题
LinkList Del_Insert(LinkList la,LinkList lb,int i,int len,int j) {
if (i<1||j<1)
{
printf("位置错误\n");
return NULL;
}
LNode* head,* tail,*pre,*q;
head = NULL;
pre = NULL;
tail = la;
q = lb;
//先进行循环拿到la链表的第i个结点的前驱,方便后续进行删除操作
//循环跳出条件为i+len-1,减1的原因是因为把截取的起始结点算上共len个结点,那么截取的终点应该是第i+len-1个结点
for (int k = 1; k < i+len-1; k++)
{
//第i-1个结点时,拿到前驱和截取部分的起始结点
if (k==i-1)
{
pre = tail;
head = tail->next;
}
//tail->next为空,说明已经到达了尾结点,如果此时还未遍历到i的位置,说明i超出了链表长度
if (tail->next == NULL && k < i)
{
printf("位置错误,la中无该结点\n");
return NULL;
}
//如果此时遍历已经达到i的位置,但已经到达尾部,且截取长度大于1,说明截取的终点超出链表长度
//注意,如果la就截取一个结点这个判定不会执行,因为此时for循环的判定条件是k<i;
if (tail->next == NULL && k >= i)
{
printf("截取错误\n");
return NULL;
}
tail = tail->next;
}
//删除操作
pre->next = tail->next;
tail->next = NULL;
printf("删除的部分为\n");
showlinklist(head);
printf("删除特定长度后的la\n");
showlinklist(la);
for (int v = 1; v < j; v++)
{
//能进入到循环里那么v肯定是小于j的,先进行判定,如果满足判定那就说明已经到尾部了,q就无法继续移动,即该结点不存在。
if (q->next == NULL)
{
printf("位置错误,lb中无该结点\n");
return NULL;
}
q = q->next;
}
tail->next = q->next;
q->next = head;
return lb;
}
验证:
LinkList Del_Insert(LinkList la,LinkList lb,int i,int len,int j) {
if (i<1||j<1)
{
printf("位置错误\n");
return NULL;
}
LNode* head,* tail,*pre,*q;
head = NULL;
pre = NULL;
tail = la;
q = lb;
//先进行循环拿到la链表的第i个结点的前驱,方便后续进行删除操作
//循环跳出条件为i+len-1,减1的原因是因为把截取的起始结点算上共len个结点,那么截取的终点应该是第i+len-1个结点
for (int k = 1; k < i+len-1; k++)
{
//第i-1个结点时,拿到前驱和截取部分的起始结点
if (k==i-1)
{
pre = tail;
head = tail->next;
}
//tail->next为空,说明已经到达了尾结点,如果此时还未遍历到i的位置,说明i超出了链表长度
if (tail->next == NULL && k < i)
{
printf("位置错误,la中无该结点\n");
return NULL;
}
//如果此时遍历已经达到i的位置,但已经到达尾部,且截取长度大于1,说明截取的终点超出链表长度
//注意,如果la就截取一个结点这个判定不会执行,因为此时for循环的判定条件是k<i;
if (tail->next == NULL && k >= i)
{
printf("截取错误\n");
return NULL;
}
tail = tail->next;
}
//删除操作
pre->next = tail->next;
tail->next = NULL;
printf("删除的部分为\n");
showlinklist(head);
printf("删除特定长度后的la\n");
showlinklist(la);
for (int v = 1; v < j; v++)
{
if (q->next == NULL)
{
printf("位置错误,lb中无该结点\n");
return NULL;
}
q = q->next;
}
tail->next = q->next;
q->next = head;
return lb;
}
int main() {
LinkList la = create_linklist();
LinkList lb = create_linklist();
printf("无头结点初始链表la\n");
showlinklist(la);
printf("无头结点初始链表lb\n");
showlinklist(lb);
//进行截取和插入,根据不同情况选取不同参数
LinkList L5 = Del_Insert(la, lb, 3, 1, 3);
if (L5!=NULL)
{
printf("插入la删除部分后的lb\n");
showlinklist(L5);
}
}
执行结果:
普通情况
先对参数进行调整
结果:
当截取的起始结点的位置大于链表la长度时:
当截取的终点位置大于链表la长度时(截取的长度要大于1):
先对参数进行调整
结果:
当截取长度为1,且截取的起始结点在尾结点时
(9)这道题合并需要讨论情况,如果A链表长度大于B链表,那么将A链表的前n项插在B链表的相同位置结点的后面。剩余部分接在后面即可。如果B链表长度大于等于A链表,那么将B链表的前m项插在A链表的相同位置结点的后面。
答案:
//第9题
LinkList merge_AB(LinkList A, LinkList B, int m, int n) {
//p,q分别遍历A,B两表,c遍历新表进行插入
LNode* p, * q,*c;
p = A->next;
q = B->next;
//创建了一个带有头结点的链表C
LinkList C = (LinkList)malloc(sizeof(LNode));
c = C;
C->next = NULL;
//A链表长度小于等于B链表
if (m<=n)
{
//因为是先接P,再接q;p走完A表后,q本身就和后面B表部分相连
while (p)
{
//给C链表接结点,然后p向后移动,注意代码顺序
c->next = p;
p = p->next;
//再接结点,q向后移动
c->next->next = q;
q = q->next;
//c跳到当前c链表的尾部。
c = c->next->next;
}
}
//A链表长度大于B链表
else {
while (q)
{
c->next = q;
q = q->next;
c->next->next = p;
p = p->next;
c = c->next->next;
}
}
return C;
}
验证:
LinkList merge_AB(LinkList A, LinkList B, int m, int n) {
//p,q分别遍历A,B两表,c遍历新表进行插入
LNode* p, * q,*c;
p = A->next;
q = B->next;
//创建了一个带有头结点的链表C
LinkList C = (LinkList)malloc(sizeof(LNode));
c = C;
C->next = NULL;
//A链表长度小于等于B链表
if (m<=n)
{
//因为是先接P,再接q;p走完A表后,q本身就和后面B表部分相连
while (p)
{
//给C链表接结点,然后p向后移动,注意代码顺序
c->next = p;
p = p->next;
//再接结点,q向后移动
c->next->next = q;
q = q->next;
//c跳到当前c链表的尾部。
c = c->next->next;
}
}
//A链表长度大于B链表
else {
while (q)
{
c->next = q;
q = q->next;
c->next->next = p;
p = p->next;
c = c->next->next;
}
}
return C;
}
int main() {
LinkList A = createLinklist();
LinkList B = createLinklist();
printf("有头结点初始链表A\n");
showlinklist(A);
int m = getsize(A);
printf("链表A的结点数为\n");
printf("%d\n", m);
printf("有头结点初始链表B\n");
showlinklist(B);
int n = getsize(B);
printf("链表B的结点数为\n");
printf("%d\n", n);
LinkList L6=merge_AB(A, B, m, n);
printf("合并链表AB\n");
showlinklist(L6);
}
执行结果:
A链表长度大于B时:
A链表长度小于B时:
两个链表长度相等时:
(10) 这个题的难点在于如何高效的查找出,通过在网上查找发现主要是两种方法,一种就是普通的遍历链表拿到链表总长度再一次遍历找到倒数第k个节点;第二种方法是直接双指针,一个指针先走k步或者k-1步,然后另一个指针和该指针同时进行移动。如果走了K步,第一个指针应该停到空指针即尾部指针的next处,如果走了k-1步,第一个指针应该停到尾部指针处。
答案:
//第10题
int findnode(LinkList list,int size,int k) {
if (k<0||k>=size)
{
return 0;
}
LNode* p, * q;
p = list;
q = list;
for (int i = 0; i < k-1; i++)
{
p = p->next;
}
while (p->next!=NULL)
{
p = p->next;
q = q->next;
}
printf("倒数第%d个结点的值为%d", k,q->data);
return 1;
}
验证:
//第10题
int findnode(LinkList list,int size,int k) {
if (k<0||k>=size)
{
return 0;
}
LNode* p, * q;
p = list;
q = list;
for (int i = 0; i < k-1; i++)
{
p = p->next;
}
while (p->next!=NULL)
{
p = p->next;
q = q->next;
}
printf("倒数第%d个结点的值为%d", k,q->data);
return 1;
}
int main() {
//第10题验证
LinkList list = createLinklist();
printf("有头结点初始链表list\n");
showlinklist(list);
int m = getsize(list);
printf("链表list的结点数为\n");
findnode(list, m, 2);
}