我有一个名为Wordd的类,它有一个成员word_,它是一个std :: list
我正在尝试在该word_中找到重复项,并在返回的列表中返回一个按字母顺序排列的列表,而不重复。到目前为止,我的代码编译和链接,但超时,可能是由于一些内部内存泄漏等。
class FindDuplicatesFunctor
{
public:
std::list<std::string> list;
std::vector<std::string> word_;
FindDuplicatesFunctor(std::vector<std::string> words): list(0), word_(words){};
void operator()(std::string const& str)
{
if(std::count(words_.begin(), words_.end(), str) > 1 && std::count(list.begin(), list.end(), str) == 0)
{
list.push_back(str);
}
list.sort();
}
};
std::list<string> Wordd::FindDuplicates() const
{
FindDuplicatesFunctor cf(word_);
return std::for_each(words_.begin(), words_.end(), cf).list;
}
为什么它没有执行任务的任何想法?
提前感谢您的帮助!
答案 0 :(得分:5)
修改回复评论:
删除重复项功能名称具有误导性,它实际上是在尝试返回序列中重复的单词列表,但该结果列表只有每个副本的一个副本 - user2624236 10 hours ago
我暗示std::sort
+ std::adjacent_find(... std::equal_to<>)
。这是实现的:
template <typename C, typename T = typename C::value_type> std::list<T> adjacent_search(C input)
{
std::sort(begin(input), end(input));
static const auto eq = std::equal_to<T>{};
static const auto neq= std::not2(eq);
std::list<T> dupes;
auto end_streak = begin(input);
auto dupe_at = std::adjacent_find(end_streak, end(input), eq);
for(auto end_streak=begin(input);
(dupe_at = std::adjacent_find(end_streak, end(input), eq)) != end(input);
end_streak = std::adjacent_find(dupe_at, end(input), neq))
{
dupes.insert(dupes.end(), *dupe_at);
}
return dupes;
}
此实现有几个很好的属性,例如线性扫描和合理的最坏情况行为(例如,如果输入包含单个值的1000个重复,则不会执行1001次无用搜索)。
但是,以下(使用一组)可能要简单得多:
// simple, but horrific performance
template <typename C, typename T = typename C::value_type> std::list<T> simple(C const& input)
{
std::set<T> dupes; // optimization, dupes.find(x) in O(log n)
for (auto it = begin(input); it != end(input); ++it)
{
if ((end(dupes) == dupes.find(*it))) // optimize by reducing find() calls
&& (std::count(it, end(input), *it) > 1))
{
dupes.insert(dupes.end(), *it);
}
}
return {begin(dupes), end(dupes)};
}
这几乎肯定会在较小的集合上表现更好,因为复制较少(结果除外)。由于std::count
中的隐式线性搜索,它可能会得到相当糟糕的最坏情况行为(对于大输入)。
我建议您直接返回std::set<T>
,而不是将其复制到列表中。
这是一个运行 Live on Coliru 的测试,显示两个版本。
现在已经过时了,因为它没有做OP想要的那样:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<std::string> input = { "unsorted", "containing", "optional", "unsorted", "duplicate", "duplicate", "values" };
std::sort(begin(input), end(input));
std::unique_copy(begin(input), end(input), std::ostream_iterator<std::string>(std::cout, " "));
std::cout << "\n";
}
输出:
containing duplicate optional unsorted values
答案 1 :(得分:1)
FindDuplicates()
函数引用word_
和words_
。看来,这两个名称是相同的,应该是哪一个,不能从代码片段中确定。
使用的算法非常慢,但是:它需要O(n * n)
时间,可能使用许多列表操作,这些操作甚至比矢量操作慢。您肯定希望使用与发布的内容相同的方法(std::sort()
后跟std::unique_copy()
)。如果您的值集非常庞大,您可能需要考虑只移动一次,并使用std::set<std::string>
保留std::unordered_set<std::string>
(或std::string const*
)或aa版本,以确定是否价值已经见过。
答案 2 :(得分:1)
排序独特擦除:
template<typename Container>
Container&& sort_unique_erase( Container&& c ) {
using std::begin; using std::end;
std::sort( begin(c), end(c) );
c.erase( std::unique( begin(c), end(c) ), end(c) );
return std::forward<Container>(c);
}
适用于任何随机访问容器,erase
范围可以是vector
中的deque
和namespace std
。
然后追加:
template<typename C1, typename C2>
C1&& append( C1&& c1, C2&& c2 ) {
using std::begin; using std::end;
c1.insert( end(c1), std::make_move_iterator( begin(c2) ), std::make_move_iterator( end(c2) ) );
return std::forward<C1>(c1);
}
template<typename C1, typename C2>
C1&& append( C1&& c1, C2& c2 ) {
using std::begin; using std::end;
c1.insert( end(c1), begin(c2), end(c2) );
return std::forward<C1>(c1);
}
并将它们绑在一起:
int main() {
std::vector<std::string> words = {"hello", "world", "my", "name", "is", "hello"};
std::list<std::string> retval;
append( retval, sort_unique_erase( std::move(words) ) );
for( auto& str : retval ) {
std::cout << str << "\n";
}
}
但是,不建议使用std::list
:在std::vector
上使用它的原因很少,或者在极少数情况下使用std::deque
。