3

文字列から文字を数え、数とcout結果で並べ替える必要があります。この目的のために、私はvectorandを使用しようとしていますstruct。これが私のコードの一部ですが、何かを実装する方法がわからないため、機能していません。

#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?

このコードで、他の間違いや潜在的な問題を確認できるかもしれません。

4

4 に答える 4

4

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;
  }
};
于 2013-02-12T19:48:54.347 に答える
2

これはあなたが必要とすることをするはずです:

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

はい、key必要はありませんが、何度も設定します。

于 2013-02-12T19:23:05.987 に答える
1

std::mapコンテナを使用して各文字の出現を保存する方が自然だと思います。文字は map のkeyであり、その出現回数は map のvalueです。ソース文字列をスキャンして を使用してこのマップを作成し、出現回数を増やすのは簡単std::map::operator[]です++

次に、キーと値を反転して、上記のマップから 2 番目のマップを作成できます。したがって、このマップはオカレンスでソートされ、この 2 番目のマップを印刷できます。この 2 番目のマップとしてa を使用する必要があることに注意してください。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

スペース文字の出現を印刷したくない場合は、簡単にフィルターで除外できます。

std::map/を使用すると、たとえば Unicode UTF-32 を使用する場合 (Unicode 文字は 256 文字よりもはるかに多いため)、非 ASCII 文字std::multimapよりもスケールアップすることに注意してください。std::vector

于 2013-02-12T20:00:19.083 に答える
1

キーを使用してコンテナにアクセスする場合(vector整数でインデックスが付けられています。これは、この場合は「キー」です)、コンテナの値フィールドにキーを再度格納する必要はありません。

したがってstruct、値フィールドのみが必要であり、出現回数をベクトルに直接格納できるため、 your は必要ありません。

アイデアは、ベクトルを最初に 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

このベクトルを並べ替えることができますが、要素が移動してインデックスが変更されるため、もちろんキーが失われます。そのような統計を処理するための優れたトリックがあります:逆 (マルチ) マップ(キー、値が逆) を使用します。

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

最後に、このマップ内のデータにアクセスして処理する方法を自分で解決する必要があります。この逆マップの優れた点は、マップがキーでソートされるため、オカレンスで自動的にソートされることです。

于 2013-02-12T19:21:14.593 に答える