C ++中(整个)单词的拆分
Posted
技术标签:
【中文标题】C ++中(整个)单词的拆分【英文标题】:Splits of (entire) words in C++ 【发布时间】:2015-12-15 10:56:48 【问题描述】:假设我们有一个文本必须由一组工作人员(map/reduce 项目中的映射器)处理:文本的每个部分(拆分)必须是一致的(没有一个词可以在两个之间拆分worker),并且拆分的大小应尽可能相等(负载平衡)。
这是我的算法:
-
将文本分成等份,每份由
off_t begin
和off_t end
(文本中的开始和结束字节)组成。
使每个拆分保持一致:如果拆分在单词中间结束,则跳转到下一个空格(并对开头执行相同操作)。如果没有这个阶段,结果可能是错误的:想想 map/reduce 中著名的“字数统计”示例。
输入(文本长度 = 29 个字符):
Hello Darkness my old friend
第 1 阶段有 4 个工人(~= 每个工人 7 个字符):
|Hello D|arkness| my old| friend|
第 2 阶段:
|Hello Darkness| |my old |friend|
这是每个拆分阶段 2 的代码:
ifstream ifs (file , ifstream::in);
char c;
string s;
if(begin>0)//begin=0 then first split: cannot break a word!
//if char before the first one is different from ' ' or '\n'
//then the split begins in the middle of a word (bad)
ifs.seekg(begin-1,ios::beg);
ifs.get(c);
if(c!=' ' && c!='\n')
getline(ifs,s,' '); //jump to the next white space
begin+=s.length();
if(begin>end)
end=begin;
ifs.seekg(end,ios::beg);
ifs.get(c);
if(c!=' ' && c!='\n' && end != size)
getline(ifs,s,' ');
end+=s.length();
如你所见,这个解决方案有两个问题:
-
拆分大小可能不平衡(查看第一个拆分和第二个拆分!)
代码有点棘手
您对改进解决方案有什么建议(在优雅和/或性能方面)?
【问题讨论】:
这里有一个镜头:在那一刻完全忘记第 2 阶段!我解释:只需分成相等的部分,处理所有这些部分,然后在第三阶段,检查单词是否损坏,并将一个工人的最后一个与下一个工人的第一个结合起来。此外,为了在第三阶段提供帮助,工作人员可以记录他们是否已经开始/结束了空间 不能那样做!正如您在更新中看到的,工作人员是 Map/Reduce 项目中的映射器。如果您知道著名的“字数统计”示例,那么您就知道不能在两个工人之间拆分一个单词!无论如何,我缺乏问题描述,对此感到抱歉! 如果我说您只是在尝试进行多线程字数统计,我会不会错。或类似的东西,也许将 fstream 转换为单词向量。工作人员是否也像传统的多线程情况一样共享内存,还是您要部署到机器集群??? 【参考方案1】:我认为从算法上讲,你不能做得更好(如果你在做 Map|Reduce,你大概有 很多 数据,所以差异会很小)。将拆分安排为Hello| Darkness| my old| friend
的工作量太大了。
可能会有轻微的改进:
估计第一次拆分的位置(在本例中为字符 7) 读一读。 向前向后寻找最近的空间。 就此分开。 如果您已经搜索过,那么您已经掌握了下一个块的开始。 更新您对下一个块应该多长时间的估计。 循环唯一的麻烦是这会使代码变得更加更复杂。
【讨论】:
这个解决方案还有一个问题:它在迭代之间引入了一个状态,这意味着没有“并行循环”(迭代的结果取决于前一个)。顺便说一句,感谢您的回答,这对串行执行很有好处!【参考方案2】:您也可以向后检查并使用字符较少的一侧直到空格。然而,这将导致额外的复杂性。对于这种简单的情况,这无关紧要,因为我希望如此小的零件会被处理得如此之快,以至于不会有任何明显的差异。
随着拆分大小的增加(比如 500 个字符甚至 1 MB),如果单词保持相对较短,不平衡将变得越来越不重要 - 所以我也不会打扰,我会“继续很简单,愚蠢”(KISS)。
【讨论】:
以上是关于C ++中(整个)单词的拆分的主要内容,如果未能解决你的问题,请参考以下文章