C ++:创建数学集来计算子集检查

时间:2016-02-27 09:42:31

标签: 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;
}

此时任何帮助都会受到赞赏。提前谢谢。

1 个答案:

答案 0 :(得分:0)

检查的方法是集合b是另一个集合的子集,是循环遍历b的每个元素并验证它是否存在于a中。如果两个集合都已排序(例如std::set的情况),则速度会更快。

你的类使用一个int数组(最好使用std::vector代替)固定大小(5,无论出于何种原因)。我认为这应该是使用动态分配的改进。

所以,要检查一个集合是否是一个子集我会建议你:

// 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