C++ にベクトル/配列があり、これらの N 要素のどれが最大の反復回数を持っているかをカウントし、最高のカウントを出力したいとします。このジョブに最適なアルゴリズムはどれか。
例:
int a = { 2, 456, 34, 3456, 2, 435, 2, 456, 2}
2 が 4 回発生するため、出力は 4 です。これが 2 が発生する最大回数です。
配列を並べ替えてから、クイック パスを実行して各数値をカウントします。アルゴリズムの複雑さは O(N*logN) です。
または、数値をキーとしてハッシュ テーブルを作成します。キーを設定した各要素のカウンターをハッシュテーブルに格納します。1 回のパスですべての要素を数えることができます。ただし、アルゴリズムの複雑さは、ハッシュ関数の複雑さに依存するようになりました。
スペースに最適化:
次に、クイックソート(たとえば)は、最大数のみを追跡しながら、アイテムを反復処理します。せいぜいO(N log N)。
速度に最適化:
個別のカウントを追跡しながら、すべての要素を繰り返し処理します。このアルゴリズムは常にO(n)になります。
RAMがあり、値が大きすぎない場合は、countingsortを使用します。
STLを利用する可能性のあるC++実装は次のとおりです。
#include <iostream>
#include <algorithm>
#include <map>
// functor
struct maxoccur
{
int _M_val;
int _M_rep;
maxoccur()
: _M_val(0),
_M_rep(0)
{}
void operator()(const std::pair<int,int> &e)
{
std::cout << "pair: " << e.first << " " << e.second << std::endl;
if ( _M_rep < e.second ) {
_M_val = e.first;
_M_rep = e.second;
}
}
};
int
main(int argc, char *argv[])
{
int a[] = {2,456,34,3456,2,435,2,456,2};
std::map<int,int> m;
// load the map
for(unsigned int i=0; i< sizeof(a)/sizeof(a[0]); i++)
m [a[i]]++;
// find the max occurence...
maxoccur ret = std::for_each(m.begin(), m.end(), maxoccur());
std::cout << "value:" << ret._M_val << " max repetition:" << ret._M_rep << std::endl;
return 0;
}
少しの疑似コード:
//split string into array firts
strsplit(numbers) //PHP function name to split a string into it's components
i=0
while( i < count(array))
{
if(isset(list[array[i]]))
{
list[array[i]]['count'] = list + 1
}
else
{
list[i]['count'] = 1
list[i]['number']
}
i=i+1
}
usort(list) //usort is a php function that sorts an array by its value not its key, Im assuming that you have something in c++ that does this
print list[0]['number'] //Should contain the most used number
それはO(n)の中にあるだろう…………しかし、事は大きな数です。of 配列は同じサイズの別の配列を取ることができます........
for(i=0;i
mar=count[o]; インデックス=o;
for(i=0;i
次に、出力は次のようになります........要素インデックスは、最大数に対して発生します。この配列の回数.......
ここで a[] は、特定の番号の最大出現数を検索する必要があるデータ配列です。配列で.......
count[] 各要素のカウントを持ちます........ 注:データの範囲が配列になることはすでにわかっています..たとえば、. その配列内のデータの範囲は 1 から 100 までです........次に、100 要素のカウント配列を保持して、インデックス付きの値を 1 ずつ増加させて発生した場合....
を使用した完全なテスト済みバージョンを次に示しstd::tr1::unordered_map
ます。
これをほぼO(n)にします。最初に n 個の入力値を反復処理して のカウントを挿入/更新しunordered_map
、次にpartial_sort_copy
O(n) を実行します。2*O(n) ~= O(n)。
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>
namespace {
// Only used in most_frequent but can't be a local class because of the member template
struct second_greater {
// Need to compare two (slightly) different types of pairs
template <typename PairA, typename PairB>
bool operator() (const PairA& a, const PairB& b) const
{ return a.second > b.second; }
};
}
template <typename Iter>
std::pair<typename std::iterator_traits<Iter>::value_type, unsigned int>
most_frequent(Iter begin, Iter end)
{
typedef typename std::iterator_traits<Iter>::value_type value_type;
typedef std::pair<value_type, unsigned int> result_type;
std::tr1::unordered_map<value_type, unsigned int> counts;
for(; begin != end; ++begin)
// This is safe because new entries in the map are defined to be initialized to 0 for
// built-in numeric types - no need to initialize them first
++ counts[*begin];
// Only need the top one at this point (could easily expand to top-n)
std::vector<result_type> top(1);
std::partial_sort_copy(counts.begin(), counts.end(),
top.begin(), top.end(), second_greater());
return top.front();
}
int main(int argc, char* argv[])
{
int a[] = { 2, 456, 34, 3456, 2, 435, 2, 456, 2 };
std::pair<int, unsigned int> m = most_frequent(a, a + (sizeof(a) / sizeof(a[0])));
std::cout << "most common = " << m.first << " (" << m.second << " instances)" << std::endl;
assert(m.first == 2);
assert(m.second == 4);
return 0;
}
要素の範囲が要素の数と比較して大きい場合、他の人が言ったように、並べ替えてスキャンするだけです。これは時間 n*log n であり、追加スペースはありません (おそらく log n 追加)。
カウントソートの問題は、値の範囲が大きい場合、ソートよりもカウント配列の初期化に時間がかかる可能性があることです。