实验思路
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)的还会快点,具体看要求而定!