我有以下代码。我有两个字符串(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 ) );
}
答案 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)
尝试打印出t1
和t2
的内容,您会看到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,