实验题目:验证集合的并与交程序
一、实验目的
- 验证集合的并与交程序。
二、实验内容
- 有两个顺序表LA和LB,把它们当成集合来使用,考虑它们的并运算和交运算。可以把顺序表当作一个抽象数据类型,直接利用它的定义来实现要求的运算。
三、设计和编码
1. 本实验用到的理论知识
线性表(顺序存储结构)
2. 算法设计
主要展示Union
和Intersection
两个函数的设计,其余的均是线性表(顺序存储结构)的常见算法。
伪代码如下
void Union(SeqList<T> &LA, SeqList<T> &LB) {
int n1 = LA.Length(), n2 = LB.Length();
for (i = 0; i < n2; i++) {
x = LB.getData(i + 1); //在LB中取一元素
k = LA.Search(x); //在LA中搜索它
if (k == 0) //若在LA中未找到插入它
{
LA.Insert(n1, x);
n1++;
} //插入到第n个表项位置}
}
}
void Intersection(SeqList<T> &LA, SeqList<T> &LB) {
int n1 = LA.Length();
for (i = 0; i < n1; i++) {
x = LA.getData(i + 1); //在LA中取一元素
k = LB.Search(x); //在LB中搜索它
if (k == 0) //若在LB中未找到
{
LA.Remove(i + 1);
n1--;
} //在LA中删除它
else i++;
}
}
时间复杂度 | 空间复杂度 |
---|---|
O ( n ) O(n) O(n) | O ( 1 ) O(1) O(1) |
3. 编码
程序清单如下(部分有修改)
// SeqList_main.cpp
// Encoding: UTF-8
#include <iostream> //引入输入输出流
using namespace std;
#include "SeqList.cpp" //引入类SeqList的声明
int main()
{
int p[5] = {1, 2, 3, 4, 5};
int q[4] = {0, 4, 5, 6};
SeqList<int> a(p, 5), b(q, 4);
cout << "a: ";
a.PrintList();
cout << "b: ";
b.PrintList();
cout << "Union(a, b): ";
Union(a, b);
a.PrintList();
SeqList<int> c(p, 5), d(q, 4);
cout << "c: ";
c.PrintList();
cout << "d: ";
d.PrintList();
cout << "Intersection(c, d): ";
Intersection(c, d);
c.PrintList();
}
// SeqList.h
// Encoding: UTF-8
#ifndef SeqList_H //避免重复包含SeqList.h头文件
#define SeqList_H
const int MaxSize = 10; //10只是示例性的数据,可以根据实际问题具体定义
template <typename DataType>
class SeqList
{
public:
SeqList() { length = 0; } //无参构造函数,创建一个空表
SeqList(DataType a[], int n); //有参构造函数
~SeqList() {} //析构函数
void Insert(int i, DataType x); //在线性表第i个位置插入值为x的元素
DataType Remove(int i); //删除线性表的第i个元素
int Search(DataType x); //求线性表中值为x的元素序号
void PrintList(); //按序号依次输出各元素
int Length(); //求性线表的长度
int getData(int i); //按位查找,在线性表中查找第i个元素
template <typename T>
friend void Union(SeqList<T> &LA, SeqList<T> &LB); //集合的并
template <typename T>
friend void Intersection(SeqList<T> &LA, SeqList<T> &LB); //集合的交
private:
DataType data[MaxSize]; //存放数据元素的数组
int length; //线性表的长度
};
#endif
// SeqList.cpp
// Encoding: UTF-8
#include <iostream> //引入输入输出流
using namespace std;
#include "SeqList.h" //引入类SeqList的声明
//以下是类SeqList的成员函数定义
template <typename DataType>
SeqList<DataType>::SeqList(DataType a[], int n)
{
if (n > MaxSize)
throw "参数非法";
for (int i = 0; i < n; i++)
data[i] = a[i];
length = n;
}
template <typename DataType>
void SeqList<DataType>::Insert(int i, DataType x)
{
if (length >= MaxSize)
throw "上溢";
if (i < 1 || i > length + 1)
throw "位置非法";
for (int j = length; j >= i; j--)
data[j] = data[j - 1]; //第j个元素存在数组下标为j-1处
data[i - 1] = x;
length++;
}
template <typename DataType>
DataType SeqList<DataType>::Remove(int i)
{
if (length == 0)
throw "下溢";
if (i < 1 || i > length)
throw "位置非法";
DataType x = data[i - 1];
for (int j = i; j < length; j++)
data[j - 1] = data[j]; //此处j已经是元素所在的数组下标
length--;
return x;
}
template <typename DataType>
int SeqList<DataType>::Search(DataType x)
{
for (int i = 0; i < length; i++)
if (data[i] == x)
return i + 1; //下标为i的元素其序号为i+1
return 0; //退出循环,说明查找失败
}
template <typename DataType>
void SeqList<DataType>::PrintList()
{
for (int i = 0; i < length; i++)
cout << data[i] << " ";
cout << endl;
}
template <typename DataType>
int SeqList<DataType>::Length() { return length; }
template <typename DataType>
int SeqList<DataType>::getData(int i)
{
if (length == 0)
throw "下溢";
if (i < 1 || i > length)
throw "位置非法";
return data[i - 1];
}
template <typename T>
void Union(SeqList<T> &LA, SeqList<T> &LB)
{
int n1 = LA.Length(), n2 = LB.Length();
int i, k;
T x;
for (i = 0; i < n2; i++)
{
x = LB.getData(i + 1); //在LB中取一元素
k = LA.Search(x); //在LA中搜索它
if (k == 0) //若在LA中未找到插入它
{
LA.Insert(n1, x);
n1++;
} //插入到第n个表项位置}
}
}
template <typename T>
void Intersection(SeqList<T> &LA, SeqList<T> &LB)
{
int n1 = LA.Length();
T x;
int k, i = 0;
while (i < n1)
{
x = LA.getData(i + 1); //在LA中取一元素
k = LB.Search(x); //在LB中搜索它
if (k == 0) //若在LB中未找到
{
LA.Remove(i + 1);
n1--;
} //在LA中删除它
else
i++;
}
}
四、运行与测试
1. 测试环境
运行环境:Windows 20H2, i7-9750H @ 2.60GHz, 16GB RAM
编译器:gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
编译命令:-g
运行终端:cmd
2. 在调试程序的过程中遇到的问题与解决方案
暂未发现异常。
3. 程序的运行结果
运行结果(符合预期)
D:\OneDrive - mail2.sysu.edu.cn\MyDocuments\code\DSA\week04\集合的并与交>SeqList_main.exe
a: 1 2 3 4 5
b: 0 4 5 6
Union(a, b): 1 2 3 4 0 6 5
c: 1 2 3 4 5
d: 0 4 5 6
Intersection(c, d): 4 5
六、总结与心得
- 链表是实现集合的并与交的一种可行的数据结构。但如果想获得更好的性能,可以考虑红黑树,C++ STL 中的 set 就是这么实现的。