关于含头结点链表实现(创建、交集、并集、差集)的解决方案

本文采取.c文件调用函数,.h文件定义功能函数的排版

    因为在做合并和交并差集的时候没有占用其他空间在执行完一个功能后,两个链表的值已经发生改变已经不是最开始的值,所以每执行一次功能后退出程序再运行执行相应的功能就行

文末有完整代码展示

一、.c文件主函数中对功能函数的调用

<1>main.c主函数代码展示

#include"Module.h"
int main()
{
	int Choice = 0;
	struct STU* List1 = CreaterList();
	printf("请输入第二个链表的数据:\n");
	struct STU* List2 = CreaterList();
	while (1)
	{
		printf("选择接下来的操作:1:链表合并2:递增链表合并3:求链表交集4:链表差集5:退出\n");
		scanf_s("%d", &Choice);
		if((Choice>=6)||(Choice<=0))//写完之后不想改了,用default:break;会简单点
		{
			printf("输入非法,请输入1-5之内的选项\n");
		}
		else
		{
			switch (Choice)
			{
			case 1:
				Merge(List1, List2);
				break;
			case 2:
				Contrast(List1, List2);
				break;
			case 3:
				Intersection(List1, List2);
				break;
			case 4:
				Differ_set(List1, List2);
				break;
			case 5:
				exit(0);
				break;
			}
		}
	}
}

<2>运行结果展示

此处对输入边界进行了处理,超出范围时会有非法输入提醒

二 、.h文件中对结构体的定义以及标准库的引用

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
typedef struct STU
{
	int data;//结构体的数据域
	struct STU* next;//结构体的指针域
};

三、链表创建函数CreaterList的定义

struct STU* CreaterList()
{
	struct STU* head = (struct STU*)malloc(sizeof(struct STU));
	head->next = NULL;//创建头结点
	struct STU* p = head;
	printf("请输入你想创建的链表元素个数:\n");
	int amount = 0;
	scanf_s("%d", &amount);
	for (int i = 0; i < amount; i++)
	{
		struct STU* knot = (struct STU*)malloc(sizeof(struct STU));//创建新结点
		//printf("请输入第%d个元素的数据,且输入为递增序列:\n", i + 1);
		scanf_s("%d", &knot->data);//将输入数据存入结点的数据域中
		p->next = knot;
		p = p->next;
		knot->next = NULL;//将链表最后一个结点指向空,否则为一个不确定的值
		p->next = NULL;
	}
	return head;
}

四:链表做最简单的合并(尾首相连)

<1>Merge函数定义代码展示

//链表合并
int Merge(struct STU* List1, struct STU* List2)
{
	struct STU* p1 = List1;
	while (p1->next != NULL)
	{
		p1 = p1->next;
	}//List1最后一个元素的指针域指向空,令其指向List2的第二个结点就好
	p1->next = List2->next;//List2含头结点所以List2->next所指向的结点才保存有需要的数据
	for (struct STU* p = List1->next; p != NULL; p = p->next)//打印合并后的链表
	{
		printf("%d\t", p->data);
	}
	printf("\n");
	return List1;
}

<2>运行结果

在这个函数中如果两链表元素有重复值,也会一起拼接在一起,此函数只实现一个简单的将两链表尾首相接的功能

五、(递增链表合并)例题要求:将两个递增的有序链表合并为一个递增的有序链表。要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中不允许有重复的数据

 <1>Contrast函数定义代码展示

// //递增链表合并为递增链表
int Contrast(struct STU* List1, struct STU* List2)
{
	struct STU* head = List1;
	struct STU* p1 = List1->next;//双指针
	struct STU* p2 = List2->next;
		while((p1!=NULL)&& (p2 != NULL))
		{
			if((p1->data < p2->data))
			{
				head->next = p1;
				p1 = p1->next;
			}
			else if ((p1->data == p2->data))
			{
				head->next = p1;//当两个链表元素中有相同的元素时将head->next随便指向p1或者p2中的哪一个
				p1 = p1->next;//当指向p1时,将p1指针后移一位
				p2 = p2->next;//同时让p2后移一位,跳过重复的值,防止重复排序
			}
			else
			{
				head->next = p2;
				p2 = p2->next;
			}
			head = head->next;
		}
		head->next = p1 == NULL ? p2 : p1;//因为是递增序列,所以当一者所有元素都排完时,直接不剩下链表的元素接到后面就好了
		for (struct STU* p = List1->next; p != NULL; p = p->next)//使用List->next旨在跳过头结点
		{
			printf("%d\t", p->data);
		}
		printf("\n");
		return List1;
}

<2>运行结果展示

当有重复元素时,排序合并后只会显示重复元素中的一个

当然如果允许合并后链表中出现重复元素,只需要将函数中对相等判断的语句删除就好(else if条件对应的语句)

六、已知两个链表A和B分别表示两个集合,其元素递增排列。请设计一个算法,用于求出A与B的交集,并将结果存放在A链表中

 <1>Intersection函数定义代码展示

//链表求交集
int Intersection(struct STU* List1, struct STU* List2)
{
	int flag = 0;
	struct STU* p1 = List1;
	struct STU* p2 = List2;
	while(p1->next!=NULL)
	{
		flag = 0;//当在List2中找到和List1中元素相同的元素时标志量将被赋值为1否则为0
		for (p2 = List2; p2->next != NULL; p2 = p2->next)
		{
			if (p2->next->data == p1->next->data)//类似于c语言中常用到的对二维数组行列的赋值外围为行内循环为列
			{//此处固定List1中的元素对List2中的元素逐一比较,当List1中的第一个数据和List2中所有的元素都比较后,
				flag = 1;//再用List1中第二个元素进行比较直至到List1中的最后一个元素
			}
		}
		if (flag != 1)//如果List1中这个位置的元素和List2中某个元素相同
		{
			struct STU* delect = p1->next;//删除该结点,并将之前指向该结点的指针指向,下一个结点
			p1->next = delect->next;
			free(delect);//释放删除结点的空间
		}
		else
		{
			p1 = p1->next;
		}
	}
	if (List1->next == NULL)
	{
		printf("两链表交集为空!!!\n");
	}
	else{
		for (struct STU* p = List1->next; p != NULL; p = p->next)//遍历交集链表,并打印
		{
			printf("%d\t", p->data);
		}
		printf("\n");
	}
	return 1;
}

<2>运行结果展示

 1、有交集链表求交集运行结果展示

2、 无交集链表求交集运行结果展示

 七、已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出两个集合A和B的差集(仅由在A中出现而不在B中出现的元素所构成的集合),并将结果以同样的形式存储,同时返回该集合元素的个数。

  做完六求交集的例题,我们可以简单思考一下,会发现在求交集的过程中我们已经把A,B集合中共有的元素已经找出来了,剩下的我们只需要把A作为全集,把交集部分的元素删除就好了

<1>Differ_set函数定义代码展示

此处和六、求链表交集代码只有细微差别

//链表求差集
int Differ_set(struct STU* List1, struct STU* List2)
{
	int flag = 0;
	struct STU* p1 = List1;
	struct STU* p2 = List2;
	while (p1->next != NULL)
	{
		flag = 0;
		for (p2 = List2; p2->next != NULL; p2 = p2->next)
		{
			if (p2->next->data == p1->next->data)
			{
				flag = 1;
				break;//找到之后直接跳出循环,可加可不加,加上代码运行时间复杂度更小
			}
		}
		if (flag == 1)
		{
			struct STU* delect = p1->next;//删除交集元素对应的结点
			p1->next = delect->next;
			free(delect);//释放空间
		}
		else
		{
			p1 = p1->next;
		}
	}
	int count = 0;
		for (struct STU* p = List1->next; p != NULL; p = p->next)
		{
			count += 1;
			printf("%d\t", p->data);
		}
		printf("存在于List1而不存在于List2的元素有%d个\n", count);
		printf("\n");
	return 1;
}

<2>运行结果展示

八、退出功能展示,无敌的exit()!

九、完整代码

<1>.c

#include"Module.h"
int main()
{
	int Choice = 0;
	struct STU* List1 = CreaterList();
	printf("请输入第二个链表的数据:\n");
	struct STU* List2 = CreaterList();
	while (1)
	{
		printf("选择接下来的操作:1:链表合并2:递增链表合并3:求链表交集4:链表差集5:退出\n");
		scanf_s("%d", &Choice);
		if((Choice>=6)||(Choice<=0))
		{
			printf("输入非法,请输入1-5之内的选项\n");
		}
		else
		{
			switch (Choice)
			{
			case 1:
				Merge(List1, List2);
				break;
			case 2:
				Contrast(List1, List2);
				break;
			case 3:
				Intersection(List1, List2);
				break;
			case 4:
				Differ_set(List1, List2);
				break;
			case 5:
				exit(0);
				break;
			}
		}
	}
}

<2>.h

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
typedef struct STU
{
	int data;
	struct STU* next;
};
struct STU* CreaterList()
{
	struct STU* head = (struct STU*)malloc(sizeof(struct STU));
	head->next = NULL;
	struct STU* p = head;
	printf("请输入你想创建的链表元素个数:\n");
	int amount = 0;
	scanf_s("%d", &amount);
	for (int i = 0; i < amount; i++)
	{
		struct STU* knot = (struct STU*)malloc(sizeof(struct STU));
		//printf("请输入第%d个元素的数据,且输入为递增序列:\n", i + 1);
		scanf_s("%d", &knot->data);
		p->next = knot;
		p = p->next;
		knot->next = NULL;
		p->next = NULL;
	}
	return head;
}
//链表合并
int Merge(struct STU* List1, struct STU* List2)
{
	struct STU* p1 = List1;
	while (p1->next != NULL)
	{
		p1 = p1->next;
	}
	p1->next = List2->next;
	for (struct STU* p = List1->next; p != NULL; p = p->next)
	{
		printf("%d\t", p->data);
	}
	printf("\n");
	return List1;
}
// //递增链表合并为递增链表
int Contrast(struct STU* List1, struct STU* List2)
{
	struct STU* head = List1;
	struct STU* p1 = List1->next;//双指针
	struct STU* p2 = List2->next;
		while((p1!=NULL)&& (p2 != NULL))
		{
			if((p1->data < p2->data))
			{
				head->next = p1;
				p1 = p1->next;
			}
			else if ((p1->data == p2->data))
			{
				head->next = p1;//当两个链表元素中有相同的元素时将head->next随便指向p1或者p2中的哪一个
				p1 = p1->next;//当指向p1时,将p1指针后移一位
				p2 = p2->next;//同时让p2后移一位,跳过重复的值,防止重复排序
			}
			else
			{
				head->next = p2;
				p2 = p2->next;
			}
			head = head->next;
		}
		head->next = p1 == NULL ? p2 : p1;//因为是递增序列,所以当一者所有元素都排完时,直接不剩下链表的元素接到后面就好了
		for (struct STU* p = List1->next; p != NULL; p = p->next)//使用List->next旨在跳过头结点
		{
			printf("%d\t", p->data);
		}
		printf("\n");
		return List1;
}
//链表求交集
int Intersection(struct STU* List1, struct STU* List2)
{
	int flag = 0;
	struct STU* p1 = List1;
	struct STU* p2 = List2;
	while(p1->next!=NULL)
	{
		flag = 0;//当在List2中找到和List1中元素相同的元素时标志量将被赋值为1否则为0
		for (p2 = List2; p2->next != NULL; p2 = p2->next)
		{
			if (p2->next->data == p1->next->data)//类似于c语言中常用到的对二维数组行列的赋值外围为行内循环为列
			{//此处固定List1中的元素对List2中的元素逐一比较,当List1中的第一个数据和List2中所有的元素都比较后,
				flag = 1;//再用List1中第二个元素进行比较直至到List1中的最后一个元素
			}
		}
		if (flag != 1)//如果List1中这个位置的元素和List2中某个元素相同
		{
			struct STU* delect = p1->next;//删除该结点,并将之前指向该结点的指针指向,下一个结点
			p1->next = delect->next;
			free(delect);//释放删除结点的空间
		}
		else
		{
			p1 = p1->next;
		}
	}
	if (List1->next == NULL)
	{
		printf("两链表交集为空!!!\n");
	}
	else{
		for (struct STU* p = List1->next; p != NULL; p = p->next)//遍历交集链表,并打印
		{
			printf("%d\t", p->data);
		}
		printf("\n");
	}
	return 1;
}
//链表求差集
int Differ_set(struct STU* List1, struct STU* List2)
{
	int flag = 0;
	struct STU* p1 = List1;
	struct STU* p2 = List2;
	while (p1->next != NULL)
	{
		flag = 0;
		for (p2 = List2; p2->next != NULL; p2 = p2->next)
		{
			if (p2->next->data == p1->next->data)
			{
				flag = 1;
				break;
			}
		}
		if (flag == 1)
		{
			struct STU* delect = p1->next;
			p1->next = delect->next;
			free(delect);
		}
		else
		{
			p1 = p1->next;
		}
	}
	int count = 0;
		for (struct STU* p = List1->next; p != NULL; p = p->next)
		{
			count += 1;
			printf("%d\t", p->data);
		}
		printf("存在于List1而不存在于List2的元素有%d个\n", count);
		printf("\n");
	return 1;
}


例题题目来源于《数据结构(C语言版 第2版)》

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值