两个递增无头结点链表合并

105 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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);
}

image.png 这组用例中,可以看出两组牌都在逐渐减少,以及后面的直接拼接

image.png 这组用例中,可以看见当两组牌的第一张一样是(如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.