通过char字符串进行最佳迭代

时间:2013-08-01 22:06:37

标签: c++ char type-conversion

这来自other question。如果我们有:

const std::string& S = ...;
int freq[CHAR_MAX-CHAR_MIN+1]={0};

以下四个循环是否相同?你更喜欢什么?

for (int           c: S) ++freq[c-CHAR_MIN];  // (1)
for (char          c: S) ++freq[c-CHAR_MIN];  // (2)
for (unsigned      c: S) ++freq[c];           // (3) <-- BAD!
for (unsigned char c: S) ++freq[c];           // (4)

3 个答案:

答案 0 :(得分:3)

2是最佳选择,因为它清楚地展示了您打算使用每个角色的内容(非常简单:作为角色)。这意味着在1,3和4中丢失。正如Rapptz所提到的,如果你有一个支持它的编译器(C ++ 11标准),你也可以使用for (auto c : S)

此外,没有必要在int(1),unsigned int(3)或unsigned char(4)中存储char,因为它们可以存储大于char的值。

答案 1 :(得分:1)

使其适当通用:

#include <limits>
#include <vector>

template <typename C, typename T = typename C::value_type>
  std::vector<unsigned> histogram(C const& container)
{
    std::vector<unsigned> result(std::numeric_limits<T>::max() - std::numeric_limits<T>::min());
    for(auto& el : container)
        result[el - std::numeric_limits<T>::min()]++;

    return result;
}

现在,这将导致大型元素类型T的无用大型结果向量(无论输入长度如何)。考虑使用地图:

// for very large char types, consider
#include <map>

template <typename C, typename T = typename C::value_type>
  std::map<T, unsigned> histogram_ex(C const& container)
{
    std::map<T, unsigned> result;

    for(auto& el : container)
        result[el]++;

    return result;
}

一些使用示范:

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

int main()
{
     auto v = histogram   (std::string ("hello world"));
     auto m = histogram_ex(std::wstring(L"hello world"));

     std::wcout << L"Sum of frequencies: " << std::accumulate(v.begin(), v.end(), 0) << "\n";

     for (auto p : m)
         std::wcout << L"'" << p.first << L"': " << p.second << L'\n';
}

打印:

Sum of frequencies: 11
' ': 1
'd': 1
'e': 1
'h': 1
'l': 3
'o': 2
'r': 1
'w': 1

全部查看 Live on Coliru

答案 2 :(得分:0)

我自己找到了答案,到目前为止没有其他答案,所以我回答了我自己的问题。

循环不等同。在(3)中,如果char已签名且值为-1,则会将其转换为unsigned,其符号扩展名为4294967295

至于个人偏好哪个循环更好,我更喜欢(4),因为它不依赖于<limits.h>

修改
(3)可能无法在非二补码系统上正常工作。所以(1)和(2)更好。将char转换为int(或size_t)时,不应听不到任何表现。