Нахождение частоты чисел в данной группе чисел - PullRequest
8 голосов
/ 28 сентября 2008

Предположим, у нас есть вектор / массив в C ++, и мы хотим подсчитать, какой из этих N элементов имеет максимальное количество повторений, и вывести наибольшее количество. Какой алгоритм лучше всего подходит для этой работы.

пример:

int a = { 2, 456, 34, 3456, 2, 435, 2, 456, 2}

вывод 4, потому что 2 происходит 4 раза. Это максимальное количество раз, которое происходит 2.

Ответы [ 9 ]

18 голосов
/ 28 сентября 2008

Сортируйте массив и затем сделайте быстрый проход, чтобы посчитать каждое число. Алгоритм имеет O (N * logN) сложность.

Либо создайте хеш-таблицу, используя номер в качестве ключа. Сохраните в хеш-таблице счетчик для каждого элемента, который вы набрали. Вы сможете сосчитать все элементы за один проход; однако теперь сложность алгоритма зависит от сложности вашей функции хеширования.

10 голосов
/ 28 сентября 2008

Оптимизировано для пространства:

Быстрая сортировка (например), затем итерация по элементам, отслеживая только наибольшее количество. В лучшем случае O (N log N).

Оптимизировано для скорости:

Итерация по всем элементам, отслеживание отдельных подсчетов. Этот алгоритм всегда будет O (n).

4 голосов
/ 28 сентября 2008

Если у вас есть ОЗУ и ваши значения не слишком велики, используйте counting sort .

2 голосов
/ 28 сентября 2008

Возможная реализация C ++, которая использует STL, может быть:

#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;
}
1 голос
/ 29 сентября 2008

Алгоритм хеширования (число построений [i] = #occurrence (i) в основном за линейное время) очень практичен, но теоретически не является строго O (n), поскольку во время процесса могут возникать коллизии хешей.

Интересным частным случаем этого вопроса является мажоритарный алгоритм, в котором вы хотите найти элемент, который присутствует как минимум в n / 2 записей массива, если такой элемент существует.

Вот быстрое объяснение и более подробное объяснение о том, как сделать это в линейное время, без всякого рода хитрости хеш-функций.

1 голос
/ 28 сентября 2008

немного псевдокода:

//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
0 голосов
/ 23 марта 2009

Это будет в O (n) ............ но дело в большом нет. массива может принимать другой массив с таким же размером ............

для (I = 0; я

Mar = кол [о]; Индекс = о;

для (I = 0; я

тогда вывод будет ......... элемент index происходит для max no. раз в этом массиве ........

здесь a [] - массив данных, в котором нам нужно найти максимальное число определенных значений no. в массиве .......

count [], имеющий количество каждого элемента .......... Примечание: мы уже знаем, что диапазон данных будет в массиве. скажем, например. данные в этом массиве колеблются от 1 до 100 ......., а затем имеют массив count из 100 элементов для отслеживания, если произошедшее увеличение увеличивает индексированное значение на один ........

0 голосов
/ 18 ноября 2008

Вот моя полная, протестированная версия с использованием 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;
}
0 голосов
/ 28 сентября 2008

Если бы диапазон элементов был большим по сравнению с количеством элементов, я бы, как уже говорили другие, просто сортировал и сканировал. Это время n * log n и нет дополнительного места (возможно, log n дополнительное).

Проблема с сортировкой подсчета состоит в том, что, если диапазон значений велик, инициализация массива подсчета может занять больше времени, чем сортировка.

...