在 C++ 中插入已排序的结构数组

发布于 2024-11-05 13:29:48 字数 1844 浏览 0 评论 0原文

我必须使用 C++ 中的数组来实现一个向量,该数组用于计算输入中唯一单词的数量。它读取输入,然后将单词添加到包含其计数和唯一单词的结构中,然后将其添加到向量中。我已经成功实现了插入。问题是我无法使插入/递增唯一字数正常工作(元素未添加到向量中)。这是我的代码:

#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include "MyVector.h"
using namespace std;

struct wordCount{
    string val;
    int count;
};

int main(int argc, char** argv) {
  enum { total, unique,individual } mode = total;
  for (int c; (c = getopt(argc, argv, "tui")) != EOF;) {
    switch(c) {
    case 't': mode = total; break;
    case 'u': mode = unique; break;
    case 'i': mode = individual; break;
    }
  }
  argc += optind;
  argv += optind;
  string word;
  Vector<wordCount> words;
  Vector<wordCount>::iterator it;
  int count = 0;
  while (cin >> word) {
    count++;
    if(mode == unique || mode == individual){
      for(it=words.begin();it != words.end();it++){
        if((it-1)->val <= word && it->val >= word){
            // Found word, increment its count
            if(it->val == word){
                it->count++;
                break;
            }
            // Otherwise insert the new unique word
            else{
              cout << "adding unique word" << endl;
              wordCount* wc;
              wc = new wordCount;
              wc->val = word;
              wc->count = 1;
              words.insert(it,*wc);
              break;
            }
        }
      }
    }
  }
  switch (mode) {
    case total: cout << "Total: " << count << endl; break;
    case unique: cout << "Unique: " << words.size() << endl; break;
    case individual:
        for(it=words.begin();it!=words.end();it++){
          cout << it->val << ": " << it->count << endl;}
        break;
  }
}

I have to implement a vector using an array in C++ that is used to count the number of unique words from the input. It reads the input and then adds to the words to a struct which contains its count and the unique word and then this is added to the vector. I have successfully implemented insert. The problem is that I can't get the inserting/ incrementing unique word count to work (elements aren't added to the vector). Here is my code:

#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include "MyVector.h"
using namespace std;

struct wordCount{
    string val;
    int count;
};

int main(int argc, char** argv) {
  enum { total, unique,individual } mode = total;
  for (int c; (c = getopt(argc, argv, "tui")) != EOF;) {
    switch(c) {
    case 't': mode = total; break;
    case 'u': mode = unique; break;
    case 'i': mode = individual; break;
    }
  }
  argc += optind;
  argv += optind;
  string word;
  Vector<wordCount> words;
  Vector<wordCount>::iterator it;
  int count = 0;
  while (cin >> word) {
    count++;
    if(mode == unique || mode == individual){
      for(it=words.begin();it != words.end();it++){
        if((it-1)->val <= word && it->val >= word){
            // Found word, increment its count
            if(it->val == word){
                it->count++;
                break;
            }
            // Otherwise insert the new unique word
            else{
              cout << "adding unique word" << endl;
              wordCount* wc;
              wc = new wordCount;
              wc->val = word;
              wc->count = 1;
              words.insert(it,*wc);
              break;
            }
        }
      }
    }
  }
  switch (mode) {
    case total: cout << "Total: " << count << endl; break;
    case unique: cout << "Unique: " << words.size() << endl; break;
    case individual:
        for(it=words.begin();it!=words.end();it++){
          cout << it->val << ": " << it->count << endl;}
        break;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凉城凉梦凉人心 2024-11-12 13:29:48

如果没有看到你的实现,很难说什么
向量。如果我们假设它符合标准容器
约定(并且尝试这样做时没有错误):你
从 it.begin() 开始迭代,但立即访问
it-1。对于标准容器来说,这是未定义的行为。 (我
不知道它会对您的 Vector` 实现做什么,
但需要一些棘手的代码才能使其工作。)

在更高的层次上,似乎存在一个基本的不一致:你是
保持向量排序,但仍然使用线性搜索。如果
你正在使用线性搜索,没有必要保留
向量排序;只需使用:(

Vector<wordCount>::iterator it = words.begin();
while ( it != words.end() && *it != word ) {
    ++ it;
}
if ( it == words.end() ) {
    //  not found, append to end...
} else {
    //  found, do whatever is appropriate...
}

虽然我可能会追加到末尾,但将迭代器恢复为
新插入的元素,并将其视为已找到)。

或者,如果您要保持向量排序,请使用二进制
搜索,而不是线性搜索。

无论哪种情况,都将搜索放在单独的函数中。 (如果这
不是家庭作业,我想说只需使用 std::vector 即可
std::find_ifstd::lower_bound。)

另外,为什么 new 位于最里面的 else 中?更合理的
方法是为 wordCount 提供一个构造函数
(将计数设置为 0),然后执行以下操作:

if ( ! found ) {
    it = words.insert( wordCount( word ) );
}
++ it->count;

found 的定义将取决于您是否使用
是否采用二分查找。就标准而言,这将是
要么:

Vector<wordCount>::iterator it
    = std::find_if( words.begin(), words.end(), MatchWord( word );
if ( it == words.end() ) {
    it = words.insert( words.end(), wordCount( word ) );
}
++ it-count;

或者

Vector<wordCount>::iterator it
    = std::lower_bound( words.begin(), words.end(), word, CompareWord() );
if ( it == words.end() || it->val != word ) {
    it = words.insert( wordCount( word ) );
++ it->count;

你应该努力做类似的事情,
一个单独的查找函数,返回 end
未找到值时插入的位置。

这使各种关注点清晰分开,并避免
代码中的过度嵌套。 (你可能应该尝试
一般来说,要避免 break,而在多重嵌套的 if 中,它是
完全不可接受——你会注意到其中之一
其他回答的人错过了他们,并误解了他们
因此控制流。)

It's hard to say anything without seeing your implementation of
Vector. If we assume it adheres to the standard container
conventions (and doesn't have an error in trying to do so): you
iterate starting with it.begin(), but immediately access
it-1. That's undefined behavior for a standard container. (I
don't know what it will do with your implementation of
Vector`,
but it would take some tricky code to make it work.)

At a higher level, there seems a basic inconsistency: you're
keeping the vector sorted, but still using linear search. If
you're using linear search, there's no point in keeping the
vector sorted; just use:

Vector<wordCount>::iterator it = words.begin();
while ( it != words.end() && *it != word ) {
    ++ it;
}
if ( it == words.end() ) {
    //  not found, append to end...
} else {
    //  found, do whatever is appropriate...
}

(although I'd probably append to end, recover the iterator to
the newly inserted element, and treat it as if it were found).

Alternatively, if you're keeping the vector sorted, use a binary
search, not a linear search.

In either case, put the search in a separate function. (If this
wasn't homework, I'd say just use std::vector and either
std::find_if or std::lower_bound.)

Also, why the new in the innermost else? A more reasonable
approach would be to provide a constructor for wordCount
(which sets the count to 0), and do something like:

if ( ! found ) {
    it = words.insert( wordCount( word ) );
}
++ it->count;

The definition of found will depend on whether you're using
binary search or not. In terms of the standard, this would be
either:

Vector<wordCount>::iterator it
    = std::find_if( words.begin(), words.end(), MatchWord( word );
if ( it == words.end() ) {
    it = words.insert( words.end(), wordCount( word ) );
}
++ it-count;

or

Vector<wordCount>::iterator it
    = std::lower_bound( words.begin(), words.end(), word, CompareWord() );
if ( it == words.end() || it->val != word ) {
    it = words.insert( wordCount( word ) );
++ it->count;

You should probably strive for something similar, with
a separate lookup function, returning either end, or the
position for the insertion when the value isn't found.

This keeps the various concerns clearly separated, and avoids
the excessive nesting in your code. (You should probably try to
avoid break in general, and in multiply nested ifs, it is
completely inacceptable—you'll notice that one of the
other people answering missed them, and misunderstood the
control flow because of it.)

执手闯天涯 2024-11-12 13:29:48

那么,为什么不使用地图呢?这正是它的用途,从一件事映射到另一件事。在您的情况下,从 string (单词)到 int (出现次数)。还是必须使用向量?

Well, why don't you use a map? That's exactly what it's for, mapping from one thing to another. From a string (the word) to an int (the number of occurences) in your case. Or do you have to use a vector?

东走西顾 2024-11-12 13:29:48

尝试使用 std::map。

Counter::Map words;
Counter count(words);

std::for_each(
    std::istream_iterator<std::string>(myInStream /*std::cin*/), 
    std::istream_iterator<std::string>(),
    count);

std::copy(
    words.begin(),
    words.end(),
    std::ostream_iterator<Counter::Map::value_type>(myOutStream /*std::cout*/, "\n"));

Counter 函子可能看起来像这样

struct Counter
{
    typedef std::map<std::string, size_t> Map;
    Counter(Map& m) : words(&m) {}
    void operator()(const std::string& word)
    {
        Map::iterator it = words->lower_bound(word);
        if (it == words->end() || it->first != word)
            words->insert(it, std::make_pair(word, 1));
        else
            ++it->second; 
    }
    Map* words;
};

使用 std::vector

struct CounterVector
{
    typedef std::vector<std::pair<std::string, size_t> > Vector;
    CounterVector(Vector& m) : words(&m) {}

    struct WordEqual
    {
        const std::string* s;
        WordEqual(const std::string& w) : s(&w) {}
        bool operator()(Vector::const_reference p) const {
            return *s == p.first;}
    };

    void operator()(const std::string& word)
    {
        Vector::iterator it = std::find_if(
            words->begin(), words->end(), WordEqual(word));
        if (it == words->end())
            words->push_back(std::make_pair(word,1));
        else
            ++it->second;
    }
    Vector* words;
};

Try to use a std::map.

Counter::Map words;
Counter count(words);

std::for_each(
    std::istream_iterator<std::string>(myInStream /*std::cin*/), 
    std::istream_iterator<std::string>(),
    count);

std::copy(
    words.begin(),
    words.end(),
    std::ostream_iterator<Counter::Map::value_type>(myOutStream /*std::cout*/, "\n"));

The Counter functor could look like this

struct Counter
{
    typedef std::map<std::string, size_t> Map;
    Counter(Map& m) : words(&m) {}
    void operator()(const std::string& word)
    {
        Map::iterator it = words->lower_bound(word);
        if (it == words->end() || it->first != word)
            words->insert(it, std::make_pair(word, 1));
        else
            ++it->second; 
    }
    Map* words;
};

Using a std::vector

struct CounterVector
{
    typedef std::vector<std::pair<std::string, size_t> > Vector;
    CounterVector(Vector& m) : words(&m) {}

    struct WordEqual
    {
        const std::string* s;
        WordEqual(const std::string& w) : s(&w) {}
        bool operator()(Vector::const_reference p) const {
            return *s == p.first;}
    };

    void operator()(const std::string& word)
    {
        Vector::iterator it = std::find_if(
            words->begin(), words->end(), WordEqual(word));
        if (it == words->end())
            words->push_back(std::make_pair(word,1));
        else
            ++it->second;
    }
    Vector* words;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文