实验思路
1.构建链表;
2.各个功能的函数
3.调试
要求:
1 实验目的
本实验是要实现求集合(用单链表表示)的并、交和差运算,通过该实验更深刻地理解线性结构的链表的特点。
2 实验内容
实现集合(用单链表表示)的并、交和差运算,并在此基础上设计一个主程序完成以下功能:
(1) 初始化集合A{'c','a','e','h'}、B{'f','h','b','g','d','a'}和空集合C
(2) 分别创建三个链表分别存放集合A、B和C
(3) 输出集合A和B的并运算结果
(4) 输出集合A和B的交运算结果
(5) 输出集合A和B的差运算结果
(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)的还会快点,具体看要求而定!