数据结构课程设计
文章目录
- 数据结构课程设计
- 1.1问题描述
- 1.2需求分析
- 1.3概要设计
- 1.4详细设计
- 1.5调试分析
- 1.6测试结果
- 1.7参考文献
- 1.8源码
1.1问题描述
编制一个能演示执行集合的交、并和差运算的程序。
要求:
-
集合元素用小写英文字母,执行各种操作应以对话方式执行。
-
算法要点:利用单链表表示集合;理解好三种运算的含义
1.2需求分析
分析:
输入:输入应该具有判断是否为小写字母的功能,如果不是小写字母,应该舍去,同时打印有效输入给用户看,用来检查输入。并且应该去除用户输入的重复元素,满足集合的互异性。并且能处理好空集的问题。
结果:实现与用户的交互功能并且能输出集合的交、并和差运算的结果。对于无效输入,也要处理。
1.3概要设计
数据类型:
采用的数据类型是单链表,单链表用来储存元素,方便后面的插入操作,具体实现如下所示:
/*链表*/
typedef struct LNode{
ElemType data;
struct LNode * next;
}LinkNode;
流程:
主程序主要就是通过用户输入来判断执行哪些操作,首先是输入操作,既要避免无效输入(非小写字母),还要去重,最后还要将有效输入打印出来。
当输入为i(Intersection)的时候,调用Intersection()函数求交集,当输入为u(Union)的时候,调用Union()函数求并集,当输入为d(Difference)的时候,调用Difference()函数求差集,本次是将A – B输出,并且输出B – A。当输入为 q 时,程序结束。而当输入是无效输入的时候,也会提醒用户。
1.4详细设计
主函数伪代码:
int main() {
定义3个链表;
初始化链表;
// InitList();
输入集合元素;
//Input();
输出有效集合元素;
//DispList();
while (flag)
{
打印功能菜单;
//menu();
switch (选择) {
case 'q':
flag <- 0;
break;
case 'i':
求交集;
//Intersection(L1, L2, L3);
break;
case 'u':
求并集;
//Union (L1, L2, L3);
break;
case 'd':
求差集;
//Difference(L1, L2, L3);
break;
default:
处理无效输入;
continue;
}
}
结束;
//return 0;
}
主函数流程图:
交集伪代码:
//交集
void Intersection(L1, L2, L3) {
while (L1不为空) {
while (L2不为空) {
if (L1元素等于L2)
break;
else
L2指向下一个元素;
}
if (找到相同元素) {
插入L3 ;
}
L1指向下一个元素;
}
}
交集流程图:
并集伪代码:
//并集
void Union (L1, L2, L3) {
// 直接将L1赋给L3
L3 = L1;
//对L2插入L3中
while (L2 -> next != NULL) {
if (L3没有这个元素) {
将这个元素插入L3 ;
}
L2指向下一个元素;
}
}
并集流程图:
差集伪代码:
1. //差集
2. void Difference(L1, L2, L3) {
3. while (L1不为空) {
4. while (L2不为空) {
5. if (L1元素等于L2)
6. break;
7. else
8. L2指向下一个元素;
9. }
10. if (找到不同元素) {
11. 插入L3 ;
12. }
13. L1指向下一个元素;
14. }
15. }
差集流程图:
1.5调试分析
调试过程中也是遇到一些问题的,首先就是单个功能测试正常,然后多次测试就失败了,然后一直在找具体原因,最后还是在删除L3链表的时候出了问题,因为自己的疏忽,不小心把L3链表全删了,导致第二次执行的时候,是找不到L3链表的,导致程序异常终止,后来经过修改,也是解决了这个问题。
以及对于输入,一开始觉得太复杂,就没有做去重操作,后来发现这样对于后面的操作带来了极大的不便,就将其修改为了去重。
对于算法复杂度,输入,交集,并集都是O(nm)的复杂度,目前没有什么好的优化方法,不过如果是改用高级语言,就可以用集合去解,也比较方便,而且如果用Python的话,这些操作都是自带的。
总结的话,还是要细心一点吧,特别是代码量一大,或者是函数调用比较多的时候,就容易犯错误,这个时候也不好修改,而且你也不知道到底是哪个环节出的问题。
1.6测试结果
测试输入:
1. // 1、两个都正常并且有无效输入
2. qwerte12DRrtyu
3. sdfdFY0egr7tgrt
4. // 2、其中一个为空集
5. (空集)
6. rwqfwerrw
7. // 3、两个都为空集
8. (空集)
9. (空集)
测试结果:
1、两个都正常并且有无效输入
2、其中一个为空集
3、两个都为空集
1.7参考文献
[1]李春葆主编;尹为民,蒋晶珏,喻丹丹,蒋林编著.数据结构教程 第5版[M].北京:清华大学出版社,2017
[2]史蒂芬·普拉达.C Primer Plus 第6版 中文版[M].北京:人民邮电出版社,2019
[3]史蒂芬·普拉达.C++ Primer Plus中文版[M].北京:人民邮电出版社,2019
1.8源码
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType; /* ElemType类型根据实际情况而定 */
/*链表*/
typedef struct LNode{
ElemType data;
struct LNode * next;
}LinkNode;
//链表的初始化
void InitList(LinkNode* &L) {
L = (LinkNode *)malloc(sizeof(LinkNode));
L->next = NULL;
}
//去重输入操作
void Input(LinkNode* &L) {
LinkNode* s, * p;
ElemType n;
scanf("%c", &n);
while (n != '\n') {
p = L ;
while (p && (p->data != n)) {//集合中不含有相同的元素
p = p ->next;
}
if (p == NULL && n >= 97 && n <= 122) {
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = n;
s->next = L->next;
L->next = s;
}
scanf("%c", &n);
}
}
不去重输入操作
//void Input(LinkNode* &L) {
// LinkNode* s;
// ElemType n;
// scanf("%c", &n);
// while (n != '\n') {
// if (n >= 97 && n <= 122) {
// s = (LinkNode*)malloc(sizeof(LinkNode));
// s->data = n;
// s->next = L->next;
// L->next = s;
// }
// scanf("%c", &n);
// }
//}
//输出操作
void DispList(LinkNode * L)
{
LinkNode * p = L -> next;
if (!p) {
printf("空集\n");
return;
}
while(p != NULL){
printf("%c ", p -> data);
p = p -> next;
}
printf("\n");
}
//链表的清空
void ClearList(LinkNode * &L) {
LinkNode * pre = L, * p = L -> next;
while (p != NULL) {
pre = p;
p = pre -> next;
free(pre);
}
L -> next = NULL;
}
//集合的并
void Union (LinkNode *&L1, LinkNode *&L2, LinkNode *&L3) {
LinkNode *p, *q, *s;
// 如果输入去重
L3 = L1;
// //如果未去重,对!1插入L3中
// p = L1 -> next;
// while (p) {
// q = L3->next;
// while (q && (q->data != p->data)) {//C3号中不含有与1号相同的元素
// q = q->next;
// }
// if (q == NULL) {
// s = (LinkNode*)malloc(sizeof(LinkNode));
// s->data = p->data;
// s->next = L3->next;
// L3->next = s;
// }
// p = p->next;
// }
//对L2插入L3中
p = L2 -> next;
while (p) {
q = L3->next;
while (q && (q->data != p->data)) {//L3中不含有与L2相同的元素
q = q->next;
}
if (q == NULL) {// //当q遍历完一次都没有找到的话,即q的最后为空时就可以将L2的元素插入L3中
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = p->data;
s->next = L3->next;
L3->next = s;
}
p = p->next;
}
}
//交集
void Intersection(LinkNode *&L1, LinkNode *&L2, LinkNode *&L3) {
LinkNode *p, *q, *r, *s;
p = L1->next;//遍历L1
while (p) {
q = L2->next;//遍历L2
while (q) {
if (p->data == q->data)
break;//找到相同的就返回
else
q = q->next;
}
if (q) {
r = (LinkNode*)malloc(sizeof(LinkNode));
r->data = p->data;
r->next = L3->next;
L3->next = r;
}
p = p->next;
}
}
//差集
void Difference(LinkNode *&L1, LinkNode *&L2, LinkNode *&L3) {
LinkNode *p, *q, *r;
p = L1->next;//遍历L1
while (p) {
q = L2->next;
while (q) {
if (q->data == p->data)
break;
else
q = q->next;
}
if (q == NULL) {//说明L2遍历完了,并且有不一样的
r = (LinkNode*)malloc(sizeof(LinkNode));
r->data = p->data;
r->next = L3->next;
L3->next = r;
}
p = p->next;
}
}
void menu(){
printf(" 功能菜单 \n");
printf("-------------------------------------------------------------\n");
printf("| q---退出程序 | i---交集运算 | u---并集运算 | d---差集运算 |\n");
printf("-------------------------------------------------------------\n");
}
int main() {
LinkNode *L1, *L2, *L3;
L1 = (LinkNode*)malloc(sizeof(LinkNode));
L2 = (LinkNode*)malloc(sizeof(LinkNode));
L3 = (LinkNode*)malloc(sizeof(LinkNode));
InitList(L1);
InitList(L2);
InitList(L3);
printf("请输入小写字母哦!\n");
printf("请输入SetA: ");
Input(L1);
printf("SetA的有效输入为: ");
DispList(L1);
printf("请输入SetB: ");
Input(L2);
printf("SetB的有效输入为: ");
DispList(L2);
char i;
int flag = 1;
while (flag)
{
menu();
printf("请选择:");
scanf("%c", &i);
getchar();
switch (i) {
case 'q':
flag = 0;
printf("感谢您的使用!");
break;
case 'i':
Intersection(L1, L2, L3);
printf("交集是:");
DispList(L3);
ClearList(L3);
break;
case 'u':
Union (L1, L2, L3);
printf("并集是:");
DispList(L3);
ClearList(L3);
break;
case 'd':
Difference(L1, L2, L3);
printf("(A-B)差集是:");
DispList(L3);
ClearList(L3);
printf("(B-A)差集是:");
Difference(L2, L1, L3);
DispList(L3);
ClearList(L3);
break;
default:
printf("无效输入!\n");
continue;
}
}
return 0;
}