不久前,我已经向一名潜在雇主提交了编码练习。答复将在下一个
上午返回,您可以从本文的主题
猜出它是什么。

我并不完全茫然,但我需要另一个程序员的观点。

练习的想法很简单:我给了一个输入文件,其中包含
汽车名称,每行一个,可以重复,但没有/>特殊顺序。

程序应输出相同的名称,但没有重复,没有在每辆汽车旁列出的出现次数,并以减少重复的顺序排列。

示例:

Honda\n Audi\n Honda\n-> Honda 2 \n Audi 1\n

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <algorithm>
#include <cctype>

using namespace std;


// helper functions ///////////////////////////////////////

// reads lines from instream
void collect_lines(istream &in, map<string, int> &lines);

// given lines->num_occurs map, reverses mapping
void reorg_by_count(map<string, int> &lines, 
                    multimap<int, string> &bycount);
///////////////////////////////////////////////////////////




int main(int ac, char* av[])
{
    istream *in;
    map<string, int> *lines = new map<string, int>();
    multimap<int, string> *lines_by_count = new multimap<int, string>();

    if (ac < 2)
    {
        in = &cin;       
    }
    else 
    {
        in = new ifstream(av[1]);
    }

    if (!in->good()) return 1;

    collect_lines(*in, *lines);
    reorg_by_count(*lines, *lines_by_count);

    if (in != &cin)
          {
        ((ifstream *)in)->close();
        delete in;
    }

    cout << "=====================\n\n";

    multimap<int, string>::reverse_iterator it 
        = lines_by_count->rbegin();

    for (; it != lines_by_count->rend(); it++)        
    {
        cout << it->second << " " << it->first << '\n';
    }


    delete lines;
    delete lines_by_count;

    return 0;
}


// Read the instream line by line, until EOF.
// Trim initial space. Empty lines skipped
void collect_lines(istream &in, map<string, int> &lines)
{
    string tmp;

    while (in.good())
    {
        getline(in, tmp);

        int i = 0;

        // trim initial space (also skips empty strings)
        for (i = 0; i < tmp.length() && !isalnum(tmp[i]); i++);
        if (i >= tmp.length()) continue;
        tmp = tmp.substr(i);

        for (i = 0; i < tmp.length(); i++)
        {
            if (!isalnum(tmp[i]))
            {
                tmp[i] = ' ';
            }

            // thus, HoNdA == Honda
            if (i == 0)
            {
                tmp[i] = toupper(tmp[i]);
            }
            else
            {
                tmp[i] = tolower(tmp[i]);
            }
        }

        // and record       the counts
        if (lines.count(tmp) == 0)
        {
            lines[tmp] = 0;
        }

        lines[tmp]++;
    }
}


// given lines->num_occurs map, reverses mapping
void reorg_by_count(map<string, int> &lines, 
                                                                                multimap<int, string> &bycount)
{
    map<string, int>::iterator it = lines.begin();

    for (; it != lines.end(); it++)
    {
      bycount.insert(pair<int, string>(it->second, it->first));       
    }
}


评论

我认为问题很简单,您付出了更多的编码工作。我相信3种优化; “时间,空间,文字”; “文本”优化称为可读性。您本可以用大约10行代码解决此问题。我现在无法提供代码;可能是明天。

这是一个很好的C答案。但是它不是C ++。

??我看到引用和STL使用...

@trinithis:C ++是一种样式。该代码可能一直在使用C ++类型,但是样式类似于C(而不是C ++)。问题在于人们认为,因为两种语言具有相同的基本语法,所以从一种语言过渡到另一种语言是微不足道的。我发现将C程序员转换为C ++确实很困难,因为您必须将他们超越整个C思维方式。因此,我不认为上面的代码是C ++。有些人使用术语“带有类的C”作为区别于C和C ++之间的语言,这里人们使用C ++功能,但仍使用C样式进行代码。

#1 楼

我看到的问题:
我的代码问题是您正在更新很多本应该是对象的东西。
map<string, int> *lines = new map<string, int>();
multimap<int, string> *lines_by_count = new multimap<int, string>();

这两个都应该只是普通对象。
map<string, int>        lines;
multimap<int, string>   lines_by_count;

这个事实会导致您被拒绝。我会看到的,也不会再直接将您的代码读到拒绝堆上了。这种风格上的根本缺陷表明您不是C ++程序员。
接下来,新对象存储在RAW指针中。你不是一个有经验的C ++程序员,这简直是天壤之别。在您的代码中,几乎应该没有任何指针。 (所有指针应由一个对象管理)。即使您手动删除了这两个文件,也不会以异常安全的方式删除它们(因此它们仍然可能泄漏)。
您正在错误地读取文件。用于读取文件的反模式(即使在C中)。您的版本存在的问题是最后一次成功的读取将读取直到但不会超过EOF。因此,文件的状态仍然很好,但是现在没有内容了。因此,您重新进入循环,第一个读取操作getline()将失败。即使它可能失败,也请您不要对此进行测试。 br />如果在地图上使用operator [],它将始终返回对内部值的引用。这意味着如果该值不存在,将插入一个。因此,无需执行此检查。只需增加值即可。如果不是,则将为您插入一个值并对其进行初始化(因此,整数将为零)。尽管不是大问题,但通常最好使用预增量。 (对于那些要说的没关系。在整数类型上这没关系。但是您必须为将来可能有人将类型更改为类对象的情况进行计划。这样一来,您将来可以证明自己的代码不会受到更改和维护问题。因此,建议先进行预递增。
您不需要执行额外的工作:
while (in.good())
{
    getline(in, tmp);

如果正确使用流库,则已经丢弃了空间。也是';'在for的末尾。这被认为是不良做法。真的很难发现,任何维护者都会问他是否真的是那样。当您的身体为空时,最好使用{}并在其{/*Deliberately empty*/}中添加注释。
这里基本上是将字符串括起来。
while (getline(in, tmp))
{
    // Line read successfully
    // Now I can processes it
}

您可以使用C ++算法库可以执行以下操作:
    if (lines.count(tmp) == 0)
    {
        lines[tmp] = 0;
    }
    lines[tmp]++;

常量正确性。
// trim initial space (also skips empty strings)
for (i = 0; i < tmp.length() && !isalnum(tmp[i]); i++);

函数不会更改参数lines。我希望它将作为const引用作为函数的文档的一部分传递,而您不会对其进行突变。这也有助于将来的维护,因为它可以防止人们意外地以后来的代码无法期望的方式更改对象。
我的最后一件事是我没有看到汽车概念的任何封装。您都将其视为文本行。如果您发明了汽车对象,则可以定义如何从流中读取汽车并将其写入流等。因此,您可以将概念封装在一个位置。
我会做这样的事情:
可能仍然会造成过度杀伤。
    for (i = 0; i < tmp.length(); i++)
    {
        if (!isalnum(tmp[i]))
        {
            tmp[i] = ' ';
        }


评论


\ $ \ begingroup \ $
+1很多优点,例如const正确性。但是,在我看来,创建Car对象实在是太过分了。
\ $ \ endgroup \ $
–阿德里安·麦卡锡(Adrian McCarthy)
2011年7月29日在20:16

\ $ \ begingroup \ $
@Adrian McCarthy:我喜欢Car对象,因为它可以让我做到这一点:while(cars >> nextCar)阅读起来非常直观。 (如果这是一个更大的程序),那么它也将代码集中在我们从流中读取汽车的位置。因此,如果我们修改汽车的表示形式,我们只需要修改一段代码,所有循环仍将起作用。
\ $ \ endgroup \ $
–马丁·约克
11年7月29日在23:02

\ $ \ begingroup \ $
@Jozin S Bazin:有很多C代码伪装成C ++(带有类的AKA C)。
\ $ \ endgroup \ $
–马丁·约克
11年7月31日在22:24

\ $ \ begingroup \ $
@Seth Carnegie:在RAII上找到一篇文章。我认为这是必须学习的C ++最重要的概念。
\ $ \ endgroup \ $
–马丁·约克
2011年8月2日在14:23

\ $ \ begingroup \ $
您错过了使用命名空间反模式添加到列表中!
\ $ \ endgroup \ $
– Toby Speight
17年12月21日在17:51

#2 楼

您正在执行手动内存管理。那不是一个好主意。实际上,这在现代C ++中根本不需要做。您可以使用自动对象,也可以使用智能指针来动态分配对象。

您根本不需要进行动态分配。代替:

map<string, int> *lines = new map<string, int>();
multimap<int, string> *lines_by_count = new multimap<int, string>();
// more things
delete lines;
delete lines_by_count;


您应该刚使用过自动对象:

map<string, int> lines;
multimap<int, string> lines_by_count;
// things


ifstream您使用过。这清楚地表明您不了解C ++最重要的方面之一。

评论


\ $ \ begingroup \ $
我认为这可能是最大的。如果他们的潜在雇主正在寻找C ++技能,那么始终使用指针和new表示相反。
\ $ \ endgroup \ $
–布伦丹·朗(Brendan Long)
2011年7月29日在18:36

\ $ \ begingroup \ $
同意。成为面试官后,我将与您分享我的想法。当我看到这类代码时,我想“这个人通常不了解堆栈,堆,引用或内存管理。他们可能首先学习Java,然后尝试跳入C / C ++。” (请注意,我不讨厌Java,我只是推测为什么要用这种方式编写此代码)。根据代码,我假设编码人员的知识尚有很大空白,然后继续前进。自从您在这里发帖,问了什么问题之后,我假设您实际上是想学习,这在编码人员中是非常好的素质。祝你好运。
\ $ \ endgroup \ $
– Tim
2011年7月29日在18:58

\ $ \ begingroup \ $
哦,还有你的for循环。您在循环之前声明了迭代器,并在不需要时将for的第一部分留为空白。
\ $ \ endgroup \ $
– Tim
11年7月29日在19:01

\ $ \ begingroup \ $
@Tim:不需要将迭代器声明也放置在for循环控制区域内,这样,行更短且更易于阅读。
\ $ \ endgroup \ $
– Ben Voigt
11年7月29日在19:41

\ $ \ begingroup \ $
@Ben:您可以在for语句中插入换行符。而且,迭代器不必要地扩展的范围远比任何长行都糟糕。
\ $ \ endgroup \ $
–法比奥·弗拉卡西(Fabio Fracassi)
2011年8月1日在8:56

#3 楼

作为评论者之一,我相信可以用几行代码(例如10行)来完成。编写长方法通常表示一个人做错了事。

我的意思是,庞大的规模会让面试官说这还不够好。我想象他们想要一小段干净的代码来完成他们所要求的,而不是书中的所有技巧都可以炫耀。

关于@Martinho的建议,我在此处添加示例

#include <iostream>
#include <list>
#include <map>

using namespace std;

bool my_pair_compare(pair<string,int> &a, pair<string,int> &b) { 
  return a.second > b.second; 
}

void my_pair_output(pair<string,int> &p) { 
  cout << p.first << " " << p.second << endl; 
}

int main() {
  map<string,int> cars;

  while (1) {
    string name;
    cin >> name;
    if (cin.eof()) break;
    cars[name]++;
  }

  list<pair<string,int> > names;

  map<string,int>::iterator citer = cars.begin();
  while (citer != cars.end()) 
    names.push_back(*citer++);

  names.sort(my_pair_compare);
  for_each(names.begin(), names.end(), my_pair_output);

  return 0;
}


评论


\ $ \ begingroup \ $
这是要点(共35行,〜10条活动行)
\ $ \ endgroup \ $
–epatel
11年7月29日在19:10

\ $ \ begingroup \ $
@epatel:在要点中张贴要点!
\ $ \ endgroup \ $
– R. Martinho Fernandes
2011年7月29日在20:16

\ $ \ begingroup \ $
最好用向量代替列表,然后用std :: sort()代替.sort()。
\ $ \ endgroup \ $
–琼·普迪(Jon Purdy)
11年7月30日在19:39

\ $ \ begingroup \ $
如果您使用像Jon Purdy建议的向量,则它的构造函数采用开始/结束对,因此您不需要while循环。只需编写:vector > names(cars.begin(),cars.end());另外三行(和一个空行)消失了!
\ $ \ endgroup \ $
– Sjoerd
11-10-29在0:31



#4 楼

我认为它可以,但是没有尝试。我认为还没有结束。在面试的情况下,他们会希望您尽力而为,而更多的是证明您知道检查退货状态和做正确的事情,即使眼前的问题很小,并且可以解决。很快,他们可能仍然希望看到完整的程序。

以下是对我突出的内容:熟悉。
无缘无故地在堆上构造了行和lines_by_count-应该只使用堆栈。
不检查分配。
处理命令行参数,也不会(a)抱怨关于多余的参数或(b)使用它们。
没有用法或'-help'支持。没有消息。


评论


\ $ \ begingroup \ $
“没有检查分配”新抛出,没有任何检查。当然,他不应该使用新的...
\ $ \ endgroup \ $
–ildjarn
11年7月29日在17:25

\ $ \ begingroup \ $
这是一个切线,我可能会被异端观点激怒,但我会说在大多数程序(包括此程序)中,检查分配是不必要的。它们失败的情况极少发生,当它们在99.9%的情况下崩溃时,您就会崩溃。在99.9%的情况下(不包括未定义行为的荒谬实施),区别只是有或没有错误消息而崩溃。如果计算机内存不足,则许多应用程序将同时崩溃,其中大多数都带有类似于segfault的错误消息,因此用户应该清楚发生了什么情况
\ $ \ endgroup \ $
–托马斯·博尼尼(Thomas Bonini)
11年7月29日在21:04

\ $ \ begingroup \ $
也不要误解我的意思;对于大型应用程序,在应用程序的全局分配管理器中进行分配失败检查当然是个好主意。我只是说,对于像这样的小型应用程序来说,这太过分了。
\ $ \ endgroup \ $
–托马斯·博尼尼(Thomas Bonini)
11年7月29日在21:06



\ $ \ begingroup \ $
是的,我同意,对于小型应用程序来说,这是矫kill过正。但是有面试问题吗?你是按书做的。
\ $ \ endgroup \ $
– Paul Beckingham
11年7月30日在1:19

\ $ \ begingroup \ $
@Andreas:“如果计算机内存不足,则许多应用程序将同时崩溃,其中大多数都带有类似segfault的错误消息,因此用户应该清楚发生了什么事情”。当“内存不足”分配失败时,计算机内存不足的想法是虚假的。因为应用程序的地址空间中没有足够的可用连续内存,所以这并不意味着其他任何人都没有。
\ $ \ endgroup \ $
– R. Martinho Fernandes
2011年7月30日在21:33

#5 楼


对于任何残酷诚实的反馈,我将不胜感激。


代码比需要的长5倍,这在一定程度上要归功于多余的代码可以完成

您需要3或4行代码才能将这些行读入地图。您使用40种方式进行诸如...进行大写更改,但是每个品牌名称中的第一个单词都没有明显的原因,没有解释。您还将去除任何非字母数字字符,这将破坏梅赛德斯-奔驰或劳斯莱斯等品牌,而没有任何解释。注释应该告诉读者代码没有的地方。例如,您说明要从每行中删除前导空格(代码已告诉我们的某些内容),但不说明您为什么不删除尾部空格(某些我们无法在代码中读取的内容)。诸如tmp之类的变量名也很差(有一些例外,例如交换例程)。我们知道变量是临时变量,因为它的范围很大。这个名字应该告诉我们它的用途。在这种情况下,它包含我们正在读取的行,因此像line这样的名称会更好。 。您可以在main的末尾删除它们,但不能在早日返回时删除它们,这是一个巨大的危险信号(考虑到这是C ++中令人头疼的主要根源)。

您还具有一些代码显示您不熟悉标准库类的工作方式(例如,将0分配给已经为0的地图条目)。


阅读问题描述后,我便在编辑器中按Tab键并编写了该程序。我最终得到的几乎是epatel发布的内容(尽管对于多字自动命名,他的代码已损坏)。我已经有近10年没有成为C ++程序员了,所以我不知道是否有一些我不知道的新东西(lamda会在这里有所帮助),但是该公司可能正在寻找简单明了的东西。

#6 楼

这是我检测到的问题:


不要使用原始指针。在c ++中,几乎不需要原始指针。如果必须,请使用智能指针。
多重地图的意义是什么?您可以定义的映射变量。
使用c强制转换很不好(在此行:((ifstream *)in)->close();
collect_lines函数过于复杂且功能过多。


评论


\ $ \ begingroup \ $
更重要的是,在此代码中根本没有理由使用指针。
\ $ \ endgroup \ $
–布伦丹·朗(Brendan Long)
2011年7月29日在18:06

\ $ \ begingroup \ $
@Brendan:实际上,由于流是多态的,因此指针很有用。但是仍然不需要动态分配。
\ $ \ endgroup \ $
– Ben Voigt
2011年7月29日在18:44

#7 楼

这是一个有趣的练习。

这很有趣,因为没有明智的人会用C ++解决这个问题。出于非常简单的原因,shell脚本中的解决方案是:

sort cars.txt | uniq -c | sort -rn


或者,如果您坚持使用以下名称: br />
不是Unix的平台将有其他工具可以用来解决它。 -C ++解决方案,或者这纯粹是用来查看您编写哪种代码的毫无意义的任务?

评论


\ $ \ begingroup \ $
这样的答案肯定值得加分(如果您还提供了c ++解决方案),但是您必须了解这是一个小练习。您能提出一个不需要花费太多时间进行编码并且可以用来衡量您的编码技能的好任务,但是它只能与C ++一起使用,而不能与Shell脚本,Python或ruby一起使用吗?您能提出并非并非毫无意义的事情吗?
\ $ \ endgroup \ $
–卡洛里·霍瓦斯(Karoly Horvath)
2011年7月30日在23:13



\ $ \ begingroup \ $
公平点。我们在公司进行的测试(使用Java)涉及一个小的但现实的已经存在的类,它是虚构的Web应用程序的一部分-实际上是一个注册处理程序,它使用用户名和密码并创建一个帐户。我们要求受访者为其添加更多功能。我不认为这是没有意义的(也许只是因为J2EE并未提供此功能,而是应该提供!)。
\ $ \ endgroup \ $
–汤姆·安德森(Tom Anderson)
2011年7月31日17:00



#8 楼

到目前为止的所有内容都可以。我看到的另外一件事是:首次访问lines [tmp]时,将自动在行中创建密钥tmp,并使用默认构造的int值(恰好为0)对其进行初始化。参见http://en.cppreference.com/w/cpp/container/map/operator_at

#9 楼

@Martinho的评论已达到目标(这对他来说是正常的),但是我认为这还不止于此。 @iammilind和@epatel可能希望有10行代码,但是根据我在上一个答案中发布的满足类似要求的代码,我认为15到20左右可能是相当合理的。

我对代码的组织方式也不感兴趣。特别是,我不喜欢让collect_lines不仅读取输入并将其放入地图中,而且不希望剪裁开头的空白并进行名字风格的大写。缺少这样做的特定要求,我可能会跳过那些面试问题,但是如果需要它们,它们应该在单独的功能中。

评论


\ $ \ begingroup \ $
10或15,认为我们至少在同一个球场;)提出了一个问题,问我是怎么想的(总共35行,〜10-15行)
\ $ \ endgroup \ $
–epatel
11年7月29日在19:48



#10 楼

为什么这些返回空值?

// reads lines from instream
void collect_lines(istream &in, map<string, int> &lines);

// given lines->num_occurs map, reverses mapping
void reorg_by_count(map<string, int> &lines, 
                    multimap<int, string> &bycount);


在这种情况下,无需通过引用,只需执行以下操作: >

评论


\ $ \ begingroup \ $
C ++ 0x之前的版本,传递引用版本将节省昂贵的副本
\ $ \ endgroup \ $
– Ben Voigt
2011年7月29日在18:43

\ $ \ begingroup \ $
@BenVoigt:我不这么认为。 RVO和NRVO可能会加入返回逻辑非复杂的函数。
\ $ \ endgroup \ $
– DeadMG
11年7月29日在19:06

\ $ \ begingroup \ $
哦,此外,这还为时过早,我先说清楚。此外,如果需要,您也可以“交换”返回值。
\ $ \ endgroup \ $
– DeadMG
11年7月29日在19:22



\ $ \ begingroup \ $
@DeadMG:是否有很多编译器甚至在未内联的函数上考虑RVO和NRVO?在使用后被定义,而且相当长,我怀疑内联会在这里发生。
\ $ \ endgroup \ $
– Ben Voigt
11年7月29日在19:43

\ $ \ begingroup \ $
@Ben Voigt:现代编译器可跨翻译单元内联。比较中,稍后在同一个TU中定义的功能是儿童游戏。另外,关于过早优化和交换的观点仍然适用。
\ $ \ endgroup \ $
– DeadMG
2011年7月30日在11:08



#11 楼

这是我对epatel答案的改进。
它从map命名空间中显式导入每个名称,以避免导入不相关的名称。
函数listcopy不会修改对,因此它们为参数获得了额外的std限定符。
逐行读取文件,这节省了几行代码,并允许包含多个单词的汽车名称。

代码如下:

#include <iostream>
#include <map>
#include <vector>

using std::cin;
using std::cout;
using std::map;
using std::pair;
using std::string;
using std::vector;

bool my_pair_less(const pair<string, int> &a, const pair<string, int> &b) {
  return b.second < a.second;
}

void my_pair_output(const pair<string, int> &p) {
  cout << p.first " " << p.second << "\n";
}

int main() {
  map<string, int> cars;

  string name;
  while (getline(cin, name)) {
    cars[name]++;
  }

  vector<pair<string, int> > names;
  copy(cars.begin(), cars.end(), back_inserter(names));
  sort(names.begin(), names.end(), my_pair_less);

  for_each(names.begin(), names.end(), my_pair_output);

  return 0;
}


#12 楼

遵循@Malvolio的想法,我猜想该任务可能已经在AWK中完成。

AWK是针对此类程序制作的。它是事件驱动的,对于axample,它在文件的每一行和结尾都有事件处理程序。它还具有地图数据结构,可以打印到stdout。

评论


\ $ \ begingroup \ $
或shell脚本。排序cars.txt | uniq -c |排序-rn,然后放松。
\ $ \ endgroup \ $
–汤姆·安德森(Tom Anderson)
2011年7月30日在18:06

\ $ \ begingroup \ $
是的,这个!添加查找功能。
\ $ \ endgroup \ $
–乔纳森·沃特莫夫(Jonathan Watmough)
2011年8月4日在17:18

#13 楼

考虑到其他人已经纠正了您的代码,我想提出一种解决该问题的方法。结束以保持递减顺序。

为此,我们可以使用一个向量来保存汽车频率信息,并使用一个映射将汽车名称链接到该向量。

用代码表达这一点要容易得多,所以就可以了:

#include <string>
#include <iostream>
#include <fstream>
#include <map>
#include <set>
#include <vector>

using namespace std;

int main( int numberOfArguments, char** arguments )
{
    typedef map< string, unsigned int > CarEntryMap;

    typedef pair< unsigned int, CarEntryMap::iterator > CarFrequency;

    typedef vector< CarFrequency > CarFrequencyVector;

    fstream file( "C:\Cars.txt" );

    if( !file.is_open() )
    {
        return 0;
    }

    CarEntryMap carEntries;

    CarFrequencyVector carFrequencies;

    string carName = "";

    while( getline( file, carName ) )
    {
        CarEntryMap::iterator it = carEntries.find( carName );

        if( it == carEntries.end() )
        {
            CarEntryMap::iterator entry = carEntries.insert( it, pair< string, unsigned int >( carName, carFrequencies.size() ) );

            carFrequencies.push_back( CarFrequency( 1, entry ) );
        }
        else
        {
            unsigned int index = it->second;

            pair< unsigned int, CarEntryMap::iterator >& currentEntry = carFrequencies[ index ];

            currentEntry.first++;

            if( index != 0 )
            {
                unsigned int updatedIndex = index;

                for( int i = index - 1; i >= 0; i-- )
                {
                    if( currentEntry.first <= carFrequencies[i].first )
                    {
                        break;
                    }

                    updatedIndex = i;
                }

                if( index != updatedIndex )
                {
                    carFrequencies[ updatedIndex ].second->second = index;

                    currentEntry.second->second = updatedIndex;

                    swap( carFrequencies[ updatedIndex ], currentEntry );
                }
            }
        }
    }

    for( CarFrequencyVector::iterator it = carFrequencies.begin(); it != carFrequencies.end(); ++it )
    {
        cout << it->second->first << " " << it->first << endl;
    }

    return 0;
}


这样,除了最后不进行排序,我们仅在汽车频率时在向量中交换两个条目订单更改。

#14 楼

这是我的看法。我使用了映射,多重集和排序谓词。

struct sort_pred {
    bool operator()(const std::pair<string,int> &left, const std::pair<string,int> &right) {
        return left.second > right.second;
    }
};

int main()
{
   multiset< pair<string,int> ,sort_pred > myset;
   map<string,int> mymap;
   readfile(mymap);
        for(map<string,int>::iterator it=mymap.begin();it!=mymap.end();it++)
        {
                myset.insert(make_pair<string,int>(it->first,it->second));
        }
        cout<<"Elements in the set:"<<endl;
        for(multiset<pair<string,int>,sort_pred >::iterator it=myset.begin();it!=myset.end();it++)
                cout<<it->first<<" "<<it->second<<endl;
                return 0;
}

void readfile(map<string,int> &t)
{
       string filename="temp.txt";
       ifstream file;
       file.open(filename.c_str());

       if(!file.is_open())
       {
              cerr<<"Error opening file : "<<filename.c_str()<<endl;
              exit(0);
       }

      string line;
      while(getline(file,line))
      {
          if(t.find(line)!=t.end())
                  t[line]++;
                  else
                  t.insert(std::make_pair(line,1));
      }
}


评论


\ $ \ begingroup \ $
您提出了替代解决方案,但尚未检查代码。请对其进行编辑,以说明您的推理(解决方案的工作原理以及如何对原始解决方案进行改进),以便所有人都可以从您的思考过程中学习。
\ $ \ endgroup \ $
– Toby Speight
17年12月21日在17:47

#15 楼

只是想出一个没有其他人提到的想法,这里的每个人都在使用地图(因为我是C#开发人员,我想像它差不多是字典/哈希表),我会想到这样做对文件中填充字符串数组进行堆排序,然后遍历它,仅计算重复数,并在每次成员与前一个成员不匹配时输出具有其计数的前一个成员。对不起,我缺乏C ++,但是就像在将文件或stdin读入数组并进行堆化之后(可能需要实现自己的文本比较器,不确定在C ++中是否需要这样做)类似。 >
我意识到这不会给任何人带来工作,我只是想提出一种不同的解决方案策略,因为他们确实知道C ++语法/ STL / etc(我不知道)。

评论


\ $ \ begingroup \ $
每个人都在使用std :: map,因为它是std :: map的教科书示例!一个简单的while(cin >> name)map [name] ++;足以阅读单词并计数。不使用std :: map是一个明确的信号,C ++不知道。
\ $ \ endgroup \ $
– Sjoerd
11-10-29在0:43



#16 楼

这就是我要回答的内容: C ++”,我会说“ C ++确实不适合这类工作,用高级语言编写并以IO绑定方式运行,速度要快一个数量级。”然后他们就不会雇用我,我会去一家公司使用一种语言,这种语言使用的语言还不够老,无法租车。 ..

后来:
想法发生了,也许招聘公司没有指定语言,那是OP的错误,选择了像C ++这样的Reagan时代的保留。 />

评论


\ $ \ begingroup \ $
Python? sha!当这种古老的语言被发明时,甚至没人听说过网络。您应该使用Clojure或Go。他们是如此新!不介意现实世界中的关联性吗?
\ $ \ endgroup \ $
–泥
11年7月30日在4:39

\ $ \ begingroup \ $
@Mud-认真地说,我不会年轻地捍卫Python,1996年,我参加了第一次世界范围的Python会议(可能有30个人在那儿),因为我写了一篇Python的互联网零售平台。第二年,我把它卖给了微软,令人惊讶的是他们仍然在卖它!对于这个问题,Clojure和Go并不是不错的选择(尽管我会争论,这并不比Python更好),尽管Mud讽刺地正确,但普及很重要,技术创新也是如此。没有字符了!
\ $ \ endgroup \ $
–马尔沃里奥
2011年7月30日14:14

\ $ \ begingroup \ $
@Malvolio:这是一个编码练习,您期望什么?他们必须执行一些简单的任务...关于高级语言:python(以及大多数其他语言)会失败的c / C ++的用法有无数:编译器,现代3d游戏,音频和视频处理,设备驱动桌面应用程序(您的浏览器,电影播放器​​,聊天等),嵌入式设备以及几乎所有其他语言(包括python)的实现。渴望用一种更高的语言解决这样一个简单的任务有多容易,这表明了您的无知,这是唯一一个不雇用您的理由。
\ $ \ endgroup \ $
–卡洛里·霍瓦斯(Karoly Horvath)
2011年7月30日在22:53



\ $ \ begingroup \ $
@yi_H-我期望什么?好吧,叫我无知,但我希望工作面试中的练习与实际工作有关。因此,如果公司正在编写设备驱动程序或视频处理程序,或者使用C ++编写的程序,则字符串处理函数是练习的不佳选择。我不知情的看法。
\ $ \ endgroup \ $
–马尔沃里奥
2011年7月31日在10:05

\ $ \ begingroup \ $
@Malvolio这项任务显然足够好,可以清除那些不太了解C ++的人。
\ $ \ endgroup \ $
– Sjoerd
11-10-29在0:46