C ++:检查vector <class>是否为vector <class> </class> </class>的子集

时间:2014-12-16 12:02:48

标签: c++ vector subset

我有以下代码。我有两个字符串(k1,k2),我通过使用空白分隔符(t1,t2)分解为令牌。然后我想检查t2中是否包含t1。 问题是,即使使用isSubset(t1,t1),我也会返回0值。 如果可能,我希望避免使用vector<string>代替vector<StringRef>。 我究竟做错了什么?输出应该是两个1,但我得到两个0。

#include<string>
#include<iostream>
#include <time.h>
#include <string.h>
#include <vector>
#include <algorithm>

using namespace std;

class StringRef
{
    private:
        char const*     begin_;
        int             size_;

    public:
        int size() const { return size_; }
        char const* begin() const { return begin_; }
        char const* end() const { return begin_ + size_; }

        std::string toString() {
             std::string value(begin_);
             return value;
        }

        StringRef( char const* const begin, int const size )
            : begin_( begin )
            , size_( size )
        {}

        bool operator<(const StringRef& s) const
        {
            return (strcmp(begin(), s.begin()) < 0);
        }
};


/************************************************
 * Checks if vector B is subset of vector A    *
 ************************************************/
bool isSubset(std::vector<StringRef> A, std::vector<StringRef> B)
{
    std::sort(A.begin(), A.end());
    std::sort(B.begin(), B.end());
    return std::includes(A.begin(), A.end(), B.begin(), B.end());
}


/************************************************
 * Split string using delimeter; returns vector *
 ************************************************/
vector<StringRef> split3( string const& str, char delimiter = ' ' )
{
    vector<StringRef>   result;

    enum State { inSpace, inToken };

    State state = inSpace;
    char const*     pTokenBegin = 0;    // Init to satisfy compiler.
    for( auto it = str.begin(); it != str.end(); ++it )
    {
        State const newState = (*it == delimiter? inSpace : inToken);
        if( newState != state )
        {
            switch( newState )
            {
            case inSpace:
                result.push_back( StringRef( pTokenBegin, &*it - pTokenBegin ) );
                break;
            case inToken:
                pTokenBegin = &*it;
            }
        }
        state = newState;
    }
    if( state == inToken )
    {
        result.push_back( StringRef( pTokenBegin, &str.back() - pTokenBegin ) );
    }
    return result;
}

int main()
{

    string k1 = "9 10";
    string k2 = "9 10 2 3";
    vector<StringRef> t1 = split3(k1,' ');
    vector<StringRef> t2 = split3(k2,' ');

    cout<<isSubset(t1,t1)<<endl;
    cout<<isSubset(t2,t1)<<endl;
    return 0;
}

编辑:------更正-------

toString更改为:

std::string toString() const {
    std::string value(begin_, size_);
    return value;
}

operator<更改为:(感谢@Mike Seymour)

bool operator<(const StringRef& s) const
{
    return (std::lexicographical_compare(begin(), end(), s.begin(), s.end()));
}

最后,在split3中,将return语句之前的if块更改为:

if( state == inToken )
{
    result.push_back( StringRef( pTokenBegin, &str.back() + 1 - pTokenBegin ) );
}

3 个答案:

答案 0 :(得分:1)

此代码存在问题。

result.push_back( StringRef( pTokenBegin, &str.back() - pTokenBegin ) );

包含一个off-by-one错误,因此最后一个令牌的大小总是太短。

return (strcmp(begin(), s.begin()) < 0);

std::string value(begin_);

依赖于\0终止的C字符串,但您没有使用\0终止的C字符串。

std::string toString() {

应该是const方法。

在我解决了所有这些问题之后,代码才有效。

答案 1 :(得分:0)

尝试打印出t1t2的内容,您会看到split3功能无效:

{9 10, 10}
{9 10 2 3, 10 2 3, 2 3, 3}

此外,您的StringRef::toString()功能已被破坏,正如迈克指出您的operator<已损坏(即使您已将其修复为使用<而不是<=)。< / p>

  

我做错了什么?

而不是写一个完整的程序,然后盯着它想知道为什么最终结果是错误的,尝试测试程序的每一部分并检查它实际上做了你认为它做的。

在这个程序中你有几个错误,找到你需要的所有单独检查每个部分并解决每个问题。试图一次解决所有问题只会让人感到困惑,因为你无法看到许多错误中的哪一个是导致意外结果的原因。

答案 2 :(得分:0)

幸运的是,c ++ 11使所有这些“观点”的恶作剧变得不必要。

std::reference_wrapper提供了一个可复制的引用(类似指针的对象,不能为null)。

您需要做的就是在std :: namespace中提供所需运算符的重载。

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>


using ConstStringRef = std::reference_wrapper<const std::string>;

namespace std {
    bool operator<(const reference_wrapper<const string>& l, const reference_wrapper<const string>& r)
    {
        return l.get() < r.get();
    }
}

using namespace std;

int main()
{

    std::string a { "hello a" };
    std::string b { "hello b" };
    const std::string c { "hello c" };

    std::vector<ConstStringRef> views { c, b, a };
    cout << "initial" << endl;
    std::copy(begin(views), end(views), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << std::endl;

    // sort using lambda
    std::sort(begin(views), end(views), [](const ConstStringRef&r1, const ConstStringRef&r2 ) { return r1.get() < r2.get(); });
    cout << "sorted using lambda" << endl;
    std::copy(begin(views), end(views), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << std::endl;

    reverse(begin(views), end(views));
    cout << "reversed" << endl;
    std::copy(begin(views), end(views), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << std::endl;

    std::sort(begin(views), end(views));
    cout << "sorted using operator<" << endl;
    std::copy(begin(views), end(views), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << std::endl;

    return 0;
}

输出:

initial
hello c, hello b, hello a, 
sorted using lambda
hello a, hello b, hello c, 
reversed
hello c, hello b, hello a, 
sorted using operator<
hello a, hello b, hello c,