检查方法是一个集合b是另一个集合的一个子集a是循环遍历b中的每个元素并验证它存在于a中。如果两个集合都被排序,这会更快(例如,这是std::set的情况)。
你的班级使用固定大小(5,无论出于何种原因)的int数组(而且最好使用std::vector)。我认为这应该是一个使用动态分配的改进。
所以,检查一组是一个子集,我会建议你是这样的:
// a.isSubset(b) check if b is a subset of a
bool Sets::isSubset(const Sets &b) {
for (int i = 0; i < b.size; i++) {
bool is_present = false;
for (int j = 0; j < size; j++) {
// b is a subset if all of its element are in a
// so check if any element of b is in a
if (arr[j] == b.arr[i]) {
is_present = true;
break;
}
}
if (!is_present) return false;
}
return true;
}
// a.isProper(b) check if b is a proper subset of a
bool Sets::isProper(const Sets &b) {
int n_equals = 0;
for (int i = 0; i < b.size; i++) {
bool is_present = false;
for (int j = 0; j < size; j++) {
// b is a prpoper subset if all of its element are in a
// but there exists at least one element of a that is not in b
if (arr[j] == b.arr[i]) {
is_present = true;
++n_equals;
break;
}
}
if (!is_present) return false;
}
return n_equals < size;
}
你的类应该作相应的修改。
编辑
为了获得更好的性能,并简化大部分最好使用一个排序容器的算法。例如,两个函数belove可能会变成:
// a.isSubset(b) check if b is a subset of a. Requires that both are sorted
bool Sets::isSubset(const Sets &b) {
for (int i = 0, j = 0; i < b.size; i++) {
// scan a, which is sorted
while (j < size && arr[j] < b.arr[i]) ++j;
if (j == size || arr[j] > b.arr[i])
// There's at least one element of b which not belongs to a
return false;
// b.arr[i] == arr[j], move on
}
// all the element of b are in a too
return true;
}
// a.isProper(b) check if b is a proper subset of a.
// It requires that both are sorted
bool Sets::isProper(const Sets &b) {
int n_equals = 0;
for (int i = 0, j = 0; i < b.size; i++) {
while (j < size && arr[j] < b.arr[i]) ++j;
if (j == size || arr[j] > b.arr[i])
// b is a prpoper subset if all of its element are in a
// but there exists at least one element of a that is not in b
return false;
++n_equals;
}
return n_equals < size;
}
要强制排序,只需修改添加元素的函数。我加了一些辅助功能太:
#include <iostream>
using namespace std;
class Sets{
private:
int size;
int allocated;
int *arr;
// It's way better using a std::vector:
// vector<int> v;
// or you can cheat and use a std::set
public:
Sets();
~Sets();
void addElement(int);
void delElement(int);
int getLowerPos(int);
int getElement(int);
int getSize();
bool doesContain(int);
bool isSubset(const Sets &);
bool isProper(const Sets &);
void printSet();
void printOrderedPairs(const Sets &);
};
Sets::Sets() : size(0), allocated(0), arr(nullptr) { }
Sets::~Sets() {
delete[] arr;
}
int Sets::getSize(){
return size;
}
// Add an element if it isn't already present, keeping the array sorted
void Sets::addElement(int x) {
int pos = this->getLowerPos(x);
if (pos < size && arr[pos] == x) return;
if (size == allocated) {
// it's time to expand the array. If it's empty, start from 8
allocated = allocated > 0 ? allocated * 2 : 8;
int *new_arr = new int[allocated];
for (int i = 0; i < pos; i++) {
new_arr[i] = arr[i];
}
for (int i = size; i > pos; --i) {
new_arr[i] = arr[i - 1];
}
delete[] arr;
arr = new_arr;
}
else {
for (int i = size; i > pos; --i) {
arr[i] = arr[i - 1];
}
}
arr[pos] = x;
++size;
}
// Remove an element from the set if it is present, keeping the array sorted
void Sets::delElement(int x) {
int pos = this->getLowerPos(x);
if (pos == size || arr[pos] != x) return;
// I move the elements and update size only, without deallocation.
--size;
for (int i = pos; i < size; ++i) {
arr[i] = arr[i + 1];
}
}
// I guess you want to return the element j of the set or -1 if it's not present
int Sets::getElement(int j){
// consider using size_t instead of int for indeces or at least unsigned int
if (j < 0 || j >= size)
// I assume all the elements are positive integers
return -1;
else
// why the temp?
return arr[j];
}
// Find the position of the lowest element in the set such that x <= arr[pos]
// with a binary search. It requires that the array is sorted.
// Return the value size if all the elements are lower then x
int Sets::getLowerPos(int x) {
int first = 0, count = size - first, step, pos = 0;
while (count > 0) {
step = count/2;
pos = first + step;
if (arr[pos] < x) {
first = ++pos;
count -= step + 1;
}
else
count = step;
}
return first;
}
// Check if x is present in the set with a binary search.
// It requires that the array is sorted
bool Sets::doesContain(int x) {
int pos = this->getLowerPos(x);
return (pos != size && arr[pos] == x);
/*
// Or directly with a simple binary search:
int low = 0, high = size - 1, pos;
while (low <= high) {
pos = low + (high - low)/2;
if (x == arr[pos])
return true;
else if (x < arr[pos])
high = pos - 1;
else
low = pos + 1;
}
return false;
*/
}
// ... isSubset() and isProper() as above ...
void Sets::printOrderedPairs(const Sets &b){
cout << "A X B = {";
for (int i = 0; i < size; i++){
for (int j = 0; j < b.size; j++){
cout << '(' << arr[i] << ", " << b.arr[j] << "), ";
}
}
cout << "\b\b} ";
}
void Sets::printSet(){
cout << '{';
for (int i = 0; i < size; i++){
cout << arr[i] << ", ";
}
cout << "\b\b} ";
}
int main(void) {
try {
Sets a;
Sets b;
a.addElement(9);
a.addElement(3);
a.addElement(7);
a.addElement(5);
a.addElement(1);
b.addElement(3);
b.addElement(7);
b.addElement(1);
b.addElement(5);
cout << "Set A is ";
a.printSet();
cout << "\nSet B is ";
b.printSet();
cout << "\n\n";
a.printOrderedPairs(b);
cout << "\n\n";
if (a.isSubset(b)) {
cout << "Set B is a subset of set A\n";
}
else {
cout << "Set B is not a subset of set A\n";
}
if (a.isProper(b)){
cout << "Set B is a proper subset of set A\n";
}
else{
cout << "Set B is not a proper subset of set A\n";
}
system("PAUSE");
}
catch (const bad_alloc& e) {
cout << "Allocation failed: " << e.what() << '\n';
}
return 0;
}
现在输出的是:
Set A is {1, 3, 5, 7, 9}
Set B is {1, 3, 5, 7}
A X B = {(1, 1), (1, 3), (1, 5), (1, 7), (3, 1), (3, 3), (3, 5), (3, 7), (5, 1), (5, 3), (5, 5), (5, 7), (7, 1), (7, 3), (7, 5), (7, 7), (9, 1), (9, 3), (9, 5), (9, 7)}
Set B is subset of set A
Set B is proper subset of set A
这是一个很好的起点,学习如何使用调试器。 –
为什么你的老师在你实际上只代表一个'Set'时要求你命名类'Sets'?我的意思是,命名**是重要的,重要的是要习惯从一开始就选择有意义的名称。 (可能比制作UML图更重要:)) –
Navta我不知道这意味着什么。弗兰克,告诉我关于它 – Radon5K