实验思路

1.构建链表;

2.各个功能的函数

3.调试


要求:

1 实验目的

本实验是要实现求集合(用单链表表示)的并、交和差运算,通过该实验更深刻地理解线性结构的链表的特点。 

实验内容

实现集合(用单链表表示)的并、交和差运算,在此基础上设计一个主程序完成以下功能:

(1) 初始化集合A{'c','a','e','h'}B{'f','h','b','g','d','a'}和空集合C

(2) 分别创建三个链表分别存放集合ABC

(3) 输出集合AB的并运算结果

(4) 输出集合AB的交运算结果

(5) 输出集合AB的差运算结果

(6) 释放三个链表


具体代码如下:

#include<stdio.h>
#include<stdlib.h>

//******宏定义参数******
#define OK 1
#define NO 0
#define DATA_MAX_SIZE 20

//******定义数据类型别名******
typedef int Status;
typedef char Excelelem;
typedef int Numelem;

//******声明数据结构******
typedef struct Node
{
	Excelelem book;
	struct Node *next;
}LNode,*LinkList;

typedef struct
{
	Excelelem name[100];
	Numelem length;
	LinkList next;
}HeadList,*HeadLinkList;

//******初始化链表******
LinkList init(int *i)
{
	LinkList Head,p,q;
	Excelelem ch;
	Head=q=NULL;
	while((ch=getchar())!='\n')
	{
		p=(LinkList)malloc(sizeof(LNode));
		p->book=ch;
		if (!(*i)) Head=q=p,(*i)++;
		else
		{
			q->next=p;
			q=p;
			(*i)++;
		}
	}
	if(p) p->next=NULL;
	return Head;
}

HeadLinkList HeadInit()
{
	//省略表头信息  Head->name
	HeadLinkList Head;
	Head=(HeadLinkList)malloc(sizeof(HeadList));
	Head->length=0;
	Head->next=init(&Head->length);
	return Head;
}

//******输出链表中的信息******
void DATA_cout(HeadLinkList Head)
{
	LinkList p=Head->next;
	while(p!=NULL)
	{
		printf("%c",p->book);
		p=p->next;
	}
	printf("\n");
	return ;
}

//******返还内存******
void DATA_Free(HeadLinkList Head)
{
	LinkList q=Head->next,p;
	while (q!=NULL)
	{
		p=q;
		q=q->next;
		free(p);
	}
	Head->length=0;
	Head->next=NULL;
	return ;
}

//******在i位置之前插入一个元素ch******
void DATA_Insert(HeadLinkList Head,Numelem k,Excelelem ch)
{
	int i=1;
	LinkList q=Head->next,p,t;
	if(Head->length && (Head->length<k || k<1))
	{
		printf("警告!%d位置不合法\n",k);
		return ;
	}
	while(p && i++ < k)
		p=q,q=q->next;
	t=(LinkList)malloc(sizeof(LNode));
	t->book=ch;
	if(k==1)
	{
		Head->next=t;
		t->next=q;
	}
	else
	{
		t->next=p;
		q->next=t;
	}
	Head->length++;
	return ;
}

//******查找是否出现字符ch******
int DATA_find(HeadLinkList Head,Excelelem ch)
{
	LinkList q=Head->next;
	while(q!=NULL && q->book!=ch)
		q=q->next;
	if(q==NULL)
		return NO;
	return OK;
}

//******AB******
void SetJiao(HeadLinkList A,HeadLinkList B,HeadLinkList C)
{
	LinkList q=A->next;
	DATA_Free(C); //初始化结果集合C,防止内存泄漏
	while (q!=NULL)
	{
		if(DATA_find(B,q->book) && !DATA_find(C,q->book))
			DATA_Insert(C,1,q->book);
		q=q->next;
	}
	return ;
}

//******A+B******
void SetBing(HeadLinkList A,HeadLinkList B,HeadLinkList C)
{
	LinkList q=A->next;
	DATA_Free(C);
	while(q!=NULL)
	{
		if(!DATA_find(C,q->book))
			DATA_Insert(C,1,q->book);
		q=q->next;
	}
	q=B->next;
	while(q!=NULL)
	{
		if(!DATA_find(C,q->book))
			DATA_Insert(C,1,q->book);
		q=q->next;
	}
	return ;
}

//******A-B******
void SetCha(HeadLinkList A,HeadLinkList B,HeadLinkList C)
{
	LinkList q=A->next;
	DATA_Free(C);
	while(q!=NULL)
	{
		if(!DATA_find(B,q->book) && !DATA_find(C,q->book))
			DATA_Insert(C,1,q->book);
		q=q->next;
	}
	return ;
}

/***************************
以上为O(n*n)算法
还有一种为O(n)算法,即在构建集合时预处理,把集合的信息映射到一张ASCLL表中,之后直接查表,免去了遍历链表的步骤,为了之后
的查表不做多余判断,在预处理的时候,要记录数据的边界

交运算:
if book[ch]==2
	C.Insert(ch);
并运算:
if book[ch]!=0
	C.Insert(ch);
差运算:
if book[ch]==1
	C.Insert(ch);

*****************************/

int main()
{
	HeadLinkList A,B,C;
	C=(HeadLinkList)malloc(sizeof(HeadList));
	C->next=NULL;
	C->length=0;
	printf("******初始化集合A******\n");
	A=HeadInit();
	printf("******初始化集合B******\n");
	B=HeadInit();
	printf("*****集合AB的结果*****\n");
	SetJiao(A,B,C);
	DATA_cout(C);
	printf("*****集合A+B的结果*****\n");
	SetBing(A,B,C);
	DATA_cout(C);
	printf("*****集合A-B的结果*****\n");
	SetCha(A,B,C);
	DATA_cout(C);
	printf("***********************\n");
	printf("*******释放内存*******\n");
	DATA_Free(A),DATA_Free(B),DATA_Free(C);
	free(A),free(B),free(C);
	printf("**********End!**********\n");
	return 0;
}

总结:

实现集合运算有挺多方法的,其具体步骤包括查找和去重,严蔚敏《数据结构C语言版》书上还有一种算法,不过也是O(n*n),思路和上面的代码基本相似,但如果输入的字符ASCLL差别不大,可以建表,这样就能一劳永逸,不过如果输入的数据较为稀疏这样时间就没啥区别了,甚至O(n*n)的还会快点,具体看要求而定!