持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情
1、求解思路
思路很简单,两个递增无头结点的链表就像两组从上往下递增排列的两组牌,比较两组牌最上面的两张,把较小的取出,排在一边,再次对比两组牌最上面的两张,把较小的去除一次排列。若碰到两组牌最上面两张牌一样大,就都取走,舍去一张,另一张在旁边排列。
2、算法解析
void merge(list A, list B)
{
list C;//C是A,B合成的新链表
list p, q, r;//这里设置了很多指针变量,他们既可以代表某个节点,也可代表此节点与之后面的节点所构成的局部链表。
//p,q是取代A,B用的,后面他俩的长度会逐渐减小。
//r是C上的某个节点,或者说r结点之后的局部链表(含r)。
p = A; q = B;//在后面的过程中,当怕p或q的头节点被取走后。p,q都会缩短。
if (p->num < q->num)//第一判断两两链表的头节点大小,把小的给C链表,即对C初始化。
{
C = p; r = C; p = p->next;
}
else
{
C = q; r = C; q = q->next;
}
while (p&&q)//循环比较,找某个链表的长度为零。
{
//每次去牌后都打印一下局面,方便我们理解整个过程。
Print(p);
Print(q);
printf("\n");//换行
if (p->num < q->num)//如果过P组牌小,就取走p的第一张。
{
r->next = p;
p = p->next;//链表缩短
r = r->next;
}
else if(p->num > q->num)//如果过q组牌小,就取走q的第一张。
{
r->next = q;
q = q->next;//链表缩短
r = r->next;
}
else {//如果,两组牌最上面的两张一样大,就都取走,且只保留一个。
r->next = p;
p = p->next;//链表缩短
q = q->next;//链表缩短
r = r->next;
//s = p; s->next = NULL; p = p->next; q = q->next;
}
}
//当某一个链表长度为零是,另一个链表还在,就直接把他接到C上。
if (p == NULL) p = q;
r->next = p;//r代表C上的某个位置。
Print(C);
}
这组用例中,可以看出两组牌都在逐渐减少,以及后面的直接拼接
这组用例中,可以看见当两组牌的第一张一样是(如3、5、7)会将两张都取走,且直保留一张。
3、完整代码
#include "stdio.h"
#include "stdlib.h"
typedef struct node
{
int num;
struct node *next;
}Node,*list;
struct node * create()//budaitoujiedian
{
struct node *head = NULL, *tail = NULL, *p;
int num;
scanf_s("%d", &num);
if (num == 0) return NULL;
while (num != 0) {
p = (struct node*)malloc(sizeof(struct node));
p->num = num;
p->next = NULL;
if (head == NULL) head = tail = p;
else { tail->next = p; tail = p; }
scanf_s("%d", &num);
}return head;
};
void Print(list l)
{
list head = l;
while (head!=NULL)
{
printf("%d ", head->num);
head = head->next;
}printf("\n");
}
//插入
Node *insert(list h, int i, list f)
{
list p;
int j;
p = h;
f = (struct node *)malloc(sizeof(struct node));
printf("要插入的节点为:\n");
scanf_s("%d", &f->num);
j = 1;
while (j<i&&p)
{
p = p->next; j++;
}
if (i == 1) {
h = f; f->next = p;
}
else {
f->next = p->next; p->next = f;
}
printf("插入成功!\n");
return h;
}
//删除节点
list Delete_node(list h, int k)
{
list p = h,q=NULL;
int j = 1;
if (h == NULL) return h;
while (j<k&&p)
{
q = p;
p = p->next;
j++;
}if (k == 1) {
h = h->next;
}
else
{
q->next = p->next;
}
free(p);
printf("删除成功!\n");
return h;
}
void merge(list A, list B)
{
list C;//AB合成新链表
list p, q, r, s;
p = A; q = B;//头节点吗???
//Print(p);
//Print(q);
//Print(A);
//Print(B);
//C = A; C->next = NULL; free(B);
//Print(C);C是不带头结点的
if (p->num < q->num)
{
C = p; r = C; p = p->next;
}
else
{
C = q; r = C; q = q->next;
}//小的给在新链表中做头节点
while (p&&q)
{
Print(p);
Print(q);
printf("\n");
if (p->num < q->num)
{
r->next = p;
p = p->next;
r = r->next;
//s = p; s->next = NULL; p = p->next;
}
else if(p->num > q->num)
{
r->next = q;
q = q->next;
r = r->next;
//s = q; s->next = NULL; q = q->next;
}
else {
r->next = p;
p = p->next;
q = q->next;
r = r->next;
//s = p; s->next = NULL; p = p->next; q = q->next;
}
//r->next = s; r = s;
}
if (p == NULL) p = q;
r->next = p;
Print(C);
}
void test01()
{
list l;
printf("单链表初始化赋值,输入0结束:\n");
l = create();
printf("打印单链表:\n");
Print(l);
list p = NULL;
printf("请输入要插入节点的位置:\n");
int s = 0;
scanf_s("%d", &s);
l = insert(l, s, p);
Print(l);
//节点删除
printf("请输入要删除节点的位置:\n");
int t;
scanf_s("%d", &t);
l = Delete_node(l, t);
Print(l);
}
void test02()
{
list A, B;
A = create();
B = create();
merge(A, B);
}
int main()
{
test02();
}
4、总结
zhi zuo bi yi, gan xie zhi chi.