2016-02-27 87 views
-2

我想知道如何检查子集和两个数组的子集。我无法弄清楚检查两个数组的子集的逻辑方法。这是我到目前为止。C++:创建一个数学集来计算子集检查

这里是我的代码: Sets.h

#ifndef SETS_H 
#define SETS_H 
using namespace std; 
class Sets{ 
private: 
    static const int SIZE = 5; 
    int arr[SIZE]; 
public: 
    Sets(); 
    void addElement(int); 
    int getElement(int); 
    int getSize(); 
    bool isSubset(Sets); 
    bool isProper(Sets); 
    void printSet(); 
    void printOrderedPairs(Sets); 
}; 

#endif 

Sets.cpp

#include "Sets.h" 
#include <iostream> 
using namespace std; 

Sets::Sets(){ 
    for (int i = 0; i < SIZE; i++){ 
     arr[i] = -1; 
    } 
} 


int Sets::getSize(){ 
    return SIZE; 
} 

void Sets::addElement(int l){ 
    for (int i = 0; i < SIZE; i++){ 
     if (arr[i] == -1){ 
      arr[i] = l; 
      break; 
     } 
    } 
} 

int Sets::getElement(int j){ 
    if (j < SIZE){ 
     return (-1); 
    } 
    else{ 
     int temp; 
     temp = arr[j]; 
     return temp; 
    } 
} 

bool Sets::isSubset(Sets b){ 
     for (int i = 0; i < SIZE; i++){ 
      for (int j = 0; j < SIZE; j++){ 
       if (arr[i] != b.arr[i]){ 
        return false; 
       } 
      } 
     } 
    return true; 
} 

bool Sets::isProper(Sets b){ 
    for (int i = 0; i < SIZE; i++){ 
     for (int j = 0; j < SIZE; j++){ 
      if (arr[i] != b.arr[j]){ 
       return false; 
      } 
     } 
    } 
    return true; 

} 

void Sets::printOrderedPairs(Sets b){ 
    cout << "A X B = {"; 
    for (int i = 0; i < SIZE-1; i++){ 
     for (int j = 0; j < SIZE; j++){ 
      cout << "(" << arr[i] << "," << b.arr[j] << ") , "; 
     } 
    } 
    cout << "}"; 
} 

void Sets::printSet(){ 
    cout << "{"; 
    for (int i = 0; i < SIZE; i++){ 
     cout << arr[i] << " ,"; 
    } 
    cout << "}"; 
} 

TestSets.cpp

#include <iostream> 
#include "Sets.h" 
using namespace std; 

int main(){ 
    Sets a; 
    Sets b; 

    a.addElement(1); 
    a.addElement(3); 
    a.addElement(5); 
    a.addElement(7); 
    a.addElement(9); 

    b.addElement(1); 
    b.addElement(3); 
    b.addElement(5); 
    b.addElement(7); 
    b.addElement(9); 
    cout << "Set A is "; 
    a.printSet(); 
    cout << endl; 
    cout << "Set B is "; 
    b.printSet(); 
    cout << "\n" << endl; 
    a.printOrderedPairs(b); 
    cout << "\n" << endl; 
    if (a.isSubset(b) == true){ 
     cout << "Set B is subset of set A" << endl; 
    } 
    else{ 
     cout << "Set B is not a subset of set A" << endl; 
    } 
    if (a.isProper(b) == true){ 
     cout << "Set B is proper subset of set A" << endl; 
    } 
    else{ 
     cout << "Set B is not a proper subset of set A" << endl; 
    } 
    system("PAUSE"); 
    return 0; 
} 

任何帮助会在这一点上欣赏。提前致谢。

+0

这是一个很好的起点,学习如何使用调试器。 –

+0

为什么你的老师在你实际上只代表一个'Set'时要求你命名类'Sets'?我的意思是,命名**是重要的,重要的是要习惯从一开始就选择有意义的名称。 (可能比制作UML图更重要:)) –

+0

Navta我不知道这意味着什么。弗兰克,告诉我关于它 – Radon5K

回答

0

检查方法是一个集合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