- 内容:如果以单链表表示集合,假设集合A用单链表LA表示,集合B用单链表LB表示,设计算法求两集合的差,即A-B。用C语言实现程序解决问题。
-
算法分析:由集合运算的规则可知,集合的差A-B中包含所有属于集合A而不属于集合B的元素。具体做法是,对于集合A中的每一个元素,在集合B的链表LB中进行查找,若存在与A中元素相同的元素,则在LA中将其删除。
首先需要定义链表结点的结构类型,然后选择使用两个while循环遍历这两个单链表,用pre和q存储相应的结点和待删除的节点,pa和pb分别用来遍历这两个单链表。
编写测试代码,假设A集合为{1,2,3,4,5,6},B集合为{1,2,3,4},则A-B集合为{5,6}。
-
概要设计:使用C语言,其中设置了以下函数
-
程序运行流程图如下:
-
测试(设计测试用例或测试代码的设计与实现,测试结果截屏)测试案例如图
- 测试结果如图所示:
测试结果显示输入字母求差集存在问题,故进行调试代码。测试代码时,当输入字母形式的集合时,会出现错误,显示“a was not declared in this scope”,主要原因在于定义data的数据类型时,定义的是int型,当输入字符型常量时,程序就会报错,因此将int data;改为char data;这时当输入字母集合时,程序正常运行,输出的是字母的ASCII码值,调试成功如图所示
源代码如下:
#include<iostream>
#include<assert.h>
using namespace std;
//定义链表结点的结构类型
struct Node
{
int elem;
Node*next;
Node(char data)
:elem(data)
, next(NULL)
{}
};
//利用函数完成集合的差运算
void Different(Node**LA, Node*LB)
{
Node*pa = *LA; //遍历A链表
//Node*pb = LB;//遍历B链表
Node *pre = NULL;//用来保存删除后结点能连接起来
Node*q;//待删除的结点
while (pa)
{
Node*pb = LB;
while (pb&&pa->elem != pb->elem)
pb = pb->next;//
if (pb)//两个结点的值相等
{
if (!pre)
{
*LA = pa->next;//指向下一个结点
}
else//第一个结点相等
{
pre->next = pa->next;//指向相等结点的后一个
}
q = pa;//释放结点
pa = pa->next;
free(q);
}
//链表B已遍历完
else
{
//更新结点的位置
pre = pa;
pa = pa->next;
}
}
}
void Printf(Node*L)
{
Node*cur = L;
while(cur)
{
cout << cur->elem << " ";
cur = cur->next;
}
cout << endl;
}
//测试代码
void Test()
{
Node*n1 = new Node('a');
Node*n2 = new Node('b');
Node*n3 = new Node('c');
Node*n4 = new Node('d');
Node*n5 = new Node('e');
Node*n6 = new Node('f');
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = n5;
n5->next = n6;
cout << "链表A" << endl;
Printf(n1);
Node*m1 = new Node('a');
Node*m2 = new Node('e');
Node*m3 = new Node('f');
Node*m4 = new Node('g');
m1->next = m2;
m2->next = m3;
m3->next = m4;
cout << "链表B" << endl;
Printf(m1);
cout << "链表的差集" << endl;
Different(&n1, m1);
Printf(n1);
}
int main()
{
Test();
system("pause");
return 0;
}