【问题标题】:How to use vector and struct?如何使用向量和结构?
【发布时间】:2013-01-28 04:53:46
【问题描述】:

我需要计算字符串中的字母,按计数和cout 结果对它们进行排序。为此,我尝试使用vectorstruct。这是我的代码的一部分,但它不起作用,因为我不知道如何实现一些东西:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

struct int_pair{
     int key;
     int value;
};  

bool sort_by_value(int_pair left, int_pair right){
    return left.value < right.value;
}

int main() {    
    string characters = "aasa asdfs dfh f ukjyhkh k wse f sdf sdfsdf";    
    vector<int_pair> most_frequent;     

    for (string::size_type i = 0; i <= characters.length(); i++) {
        int int_char = (int)characters[i];
        most_frequent[int_char]++; <-- I want to do something like this, but it's not working 
    }

    sort(most_frequent.begin(), most_frequent.end(), sort_by_value);

    for (vector<int_pair>::iterator it = most_frequent.begin(); it != most_frequent.end(); ++it) <-- is this call correct?
        cout << " " << it->key << ":" << it->value << endl;    

    return 0;
}

在这段代码中,我有 2 个部分我不知道如何处理:

most_frequent[int_char]++; <-- I want to do something like this, but it's not working 

for (vector<int_pair>::iterator it = most_frequent.begin(); it != most_frequent.end(); ++it) <-- is this call correct?

也许您可以在此代码中看到任何其他错误和潜在问题。

【问题讨论】:

  • 这是使用矢量的练习吗?因为 map 或 hashmap 可能更适合小字符串。
  • @PeteKirkham 不,不是。这是我的解决方案。

标签: c++ data-structures vector struct


【解决方案1】:

使用键访问容器时(vector 使用整数索引,在您的情况下为“键”),您不必再次将键存储在容器的值字段中。

所以你不需要你的struct,因为你只需要值字段并且可以将出现的次数直接存储在向量中。

这个想法是在开始时用 256 个整数填充向量,全部初始化为零。然后,使用向量索引作为您的“键”(字符代码)来访问元素(出现次数)。

这将产生类似这样的代码:

// initialize with 256 entries, one for each character:
vector<int> counts(256);

for (string::size_type i = 0; i <= characters.length(); i++) {
    // for each occurrence of a character, increase the value in the vector:
    int int_char = (int)characters[i];
    counts[int_char]++;  
}   

向量填充完成后,您可以使用std::max_element 算法找到最大值(不仅是值,还可以找到存储它的键):

vector<int>::iterator most_frequent =
        std::max_element(counts.begin(), counts.end());

// getting the character (index within the container, "key"):
std::cout << (char)(most_frequent - counts.begin());

// the number of occurrences ("value"):
std::cout << (*most_frequent);

这是您的更改示例(仅打印最常见的字符,这里是空格,所以您看不到它):http://ideone.com/94GfZz

可以对该向量进行排序,但是,您当然会丢失密钥,因为元素会移动并更改其索引。有一个很好的技巧来处理这样的统计数据:使用 reversed (multi)map(key, value reversed):

multimap<int,int> keyForOccurrence;
for (vector<int>::iterator i = counts.begin(); i != counts.end(); ++i) {
    int occurrences = *i;
    int character = i - counts.begin();
    keyForOccurrence.insert(std::pair<int,int>(occurrences, character));
}

更新代码:http://ideone.com/Ub5rnL

您现在应该自己解决的最后一件事是如何访问和处理此地图中的数据。这个反转映射的奇特之处在于它现在自动按出现排序,因为映射是按键排序的。

【讨论】:

  • 我需要计算所有字母,而不仅仅是最常用的一个。
  • 向量包含所有这些。
  • @viakondratiuk:leemes 的代码应该是计算所有字母的好起点。你确定不希望他为你做所有的功课吗?
  • @leemes 这个任务还有其他方法吗?我在向量中有很多 0 值,我认为这是一个开销。
  • 这将占用 1KB。我怀疑这将是一个问题。您可以限制为 ASCII 字符并仅使用 128 个条目(但如果您决定这样做,请检查每个字符的 &lt;128 并为 ASCII 以外的字符实现大小写,否则您的程序会崩溃)。像map 这样的数据结构显然更昂贵。
【解决方案2】:

这应该可以满足您的需要:

most_frequent[int_char].key = int_char;
most_frequent[int_char].value++; 

是的,它会多次设置key,尽管它不需要这样做。

【讨论】:

  • 我用你的代码更新了这一行most_frequent[int_char]++;,现在得到:Segmentation fault (core dumped)
  • @viakondratiuk 这是因为你的向量是空的。禁止访问向量中不存在的元素(与映射相反)您必须在开头用 256 个值填充向量(将 256 传递给 vector 的构造函数)。
  • @viakondratiuk: vector &lt;int_pair&gt; most_frequent(256);
  • 是的,它正在工作。但是使用这种方法,我得到了很多 0 值。我怎样才能避免它?
  • if (it.value != 0) print value; else do nothing?
【解决方案3】:

我会使用 std::map 来确定每个字母的频率,然后将其复制到多重映射中,同时反转键和值以使它们按顺序排列。

#include <iostream>
#include <map>
#include <algorithm>

template<class T, class U>
std::pair<U,T> flip_pair(const std::pair<T,U>& p) {
  return std::make_pair(p.second,p.first);
}

int main(){
  std::string characters = "zxcvopqiuweriuzxchajksdui";
  std::map<char,int> freq;
  std::multimap<int,char> rev_freq;

  // Calculate the frequency of each letter.
  for(char c: characters){
    freq[c]++;
  }

  // Copy the results into a multimap with the key and value flipped 
  std::transform(std::begin(freq), std::end(freq), 
                 std::inserter(rev_freq, rev_freq.begin()), 
                 flip_pair<char,int>);

  // Print out the results in order.
  for(std::pair<int,char> p : rev_freq){
    std::cout << p.first << ": " << p.second << std::endl;
  }
};

【讨论】:

    【解决方案4】:

    我发现使用 std::map 容器来存储每个出现的字符更为自然。字符是map的key,它的出现次数是map的value。 使用std::map::operator[]++ 可以轻松扫描源字符串并构建此映射以增加出现次数。

    然后,您可以从上面的地图构建第二张地图,其键和值反转:因此该地图将按出现次数排序,然后您可以打印这第二张地图。 请注意,您必须使用 std::multimap 作为第二个映射,因为它的键(即出现次数)可以重复。

    示例代码如下(我用VS2010 SP1/VC10测试过):

    #include <stddef.h>     // for size_t
    #include <algorithm>    // for std::transform
    #include <functional>   // for std::greater
    #include <iostream>     // for std::cout
    #include <iterator>     // for std::inserter
    #include <map>          // for std::map, std::multimap
    #include <ostream>      // for std::endl
    #include <string>       // for std::string
    #include <utility>      // for std::pair
    using namespace std;
    
    int main() 
    {    
        string str = "aasa asdfs dfh f ukjyhkh k wse f sdf sdfsdf";    
    
        // Build the occurrences map (char -> occurrences)
        map<char, size_t> freq;     
        for (size_t i = 0; i < str.length(); ++i)
            freq[ str[i] ]++;
    
        // Build a new map from previous map with inverted <key, value> pairs,
        // so this new map will be sorted by old map's value (i.e. char's
        // occurrences), which is new map's key. 
        // Use the std::greater comparator to sort in descending order.
        multimap<size_t, char, greater<size_t>> sorted_freq; 
        transform(
            freq.begin(), freq.end(),                       // source 
            inserter(sorted_freq, sorted_freq.begin()),     // destination
            [](const pair<char, size_t>& p)                 // invert key<->value
            { 
                return pair<size_t, char>(p.second, p.first); 
            }
        );
    
        // Print results    
        for (auto it = sorted_freq.begin(); it != sorted_freq.end(); ++it)
            cout << it->second << ": " << it->first << endl;
    }
    

    输出:

     : 9
    s: 7
    f: 7
    d: 5
    a: 4
    k: 3
    h: 3
    u: 1
    w: 1
    y: 1
    j: 1
    e: 1
    

    如果您不想打印出现的空格字符,可以轻松将其过滤掉。

    请注意,对于非 ASCII 字符,使用 std::map/std::multimap 也将比 std::vector 更好地扩展,例如如果您使用 Unicode UTF-32(因为 Unicode 字符远不止 256 个)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-02
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      • 1970-01-01
      相关资源
      最近更新 更多