12

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

Полезно ли использовать поиск в ковше для этого?

На самом деле я обнаружил, что вопрос Calculating frequency distribution of a collection with .Net/C#

Но я не понимаю, как использовать ведра для этой цели вызвать размер каждого сегмента может быть различным в моей ситуации.

EDIT: После всех обсуждений у меня есть решение для внутреннего/внешнего контура, но все же я хочу исключить внутреннюю петлю с помощью словаря, чтобы получить производительность O (n) в этом случае, если я правильно понял, мне нужен хэш-вход значения в индекс ковша. Итак, нам нужна какая-то хеш-функция с сложностью O (1)? Есть идеи, как это сделать?

+1

Вы можете описать массив границ немного лучше? Существует ли какая-либо взаимосвязь между различными границами (т. Е. Они являются последовательными) или они полностью случайны по размеру и «местоположению»? Я предполагаю, что массив границ полностью охватывает диапазон возможных значений - это правда? Кроме того, я предполагаю, что нет совпадений - правильно? –

+0

самый быстрый в значении большого «О» или в смысле небольшого кода? Простым подходом было бы написать себе функцию Func и использовать ее с Linqs .GroupBy, чтобы сгруппировать ее в «Ведра», но для этого могут быть более быстрые способы вычисления. – Carsten

+0

Да, вы правы. Граничные значения монотонно возрастают по значению. Они не перекрываются и охватывают диапазон возможных значений. Так, например: 0, 10, 50, 100, 120. – Andrey

ответ

4

Bucket Sort уже O (n^2) наихудший случай, поэтому я бы просто сделал простой внутренний/внешний цикл здесь. Поскольку ваш массив ведра обязательно короче, чем ваш входной массив, держите его во внутреннем цикле. Поскольку вы используете пользовательские размеры ведра, на самом деле нет математических трюков, которые могут устранить этот внутренний цикл.

int[] freq = new int[buckets.length - 1]; 
foreach(int d in input) 
{ 
    for(int i = 0; i < buckets.length - 1; i++) 
    { 
     if(d >= buckets[i] && d < buckets[i+1]) 
     { 
      freq[i]++; 
      break; 
     } 
    } 
} 

Это также O (n^2) наихудший случай, но вы не можете победить простоту кода. Я бы не стал беспокоиться об оптимизации, пока это не станет реальной проблемой. Если у вас большой массив ведра, вы можете использовать двоичный поиск. Но, поскольку частотные распределения обычно составляют < 100 элементов, я сомневаюсь, что вы увидите много преимуществ в реальном времени.

+1

Что вы думаете о реализации BucketizedHashtable, как показано на Java? Или как насчет сортировки массива в начале выполнения, имеет ли смысл? –

+0

Исключить внутренний цикл с помощью словаря ', чтобы получить амортизацию O (n) perf. –

+0

@Hans Что значит? Я действительно не понимаю :( – Andrey

1

Если входной массив представляет реальные данные (с его узорами) и массив границ велик, чтобы перебирать его снова и снова во внутреннем цикле вы можете рассмотреть следующий подход:

  • Прежде всего рода ваш входной массив. Если вы работаете с реальными данными , я бы рекомендовал рассмотреть Timsort - Wiki. Он обеспечивает очень хорошие гарантии производительности для моделей, которые можно увидеть в данных реального мира.

  • траверса через отсортированный массив и сравнить его с первым значением в массиве границ:

    • Если значение входного массива меньше, то граница - частоты приращения счетчика для этой границы
    • Если значение входной массив больше, чем граница - перейти к следующему значению в массиве границ и увеличить счетчик для новой границы.

В коде может выглядеть следующим образом:

Timsort(myArray); 
int boundPos; 
boundaries = GetBoundaries(); //assume the boundaries is a Dictionary<int,int>() 

for (int i = 0; i<myArray.Lenght; i++) { 
    if (myArray[i]<boundaries[boundPos]) { 
    boundaries[boubdPos]++; 
    } 
    else { 
    boundPos++; 
    boundaries[boubdPos]++; 
    } 
} 
+1

представлены массивом значений. но как насчет сложности? как я понял для Timsort в худшем случае O (nlogn) + O (n) для циклирования. Я думаю, что внутренний/внешний цикл с бинарным поиском должен быть лучше? – Andrey

+2

Не совсем верно. Это произойдет, если в середине будет пустое ведро. То есть в отсортированном массиве есть два входных значения, которые находятся рядом друг с другом, но идут в ведра, которые не находятся рядом друг с другом. Но это можно исправить. В общем, это очень хорошая идея. В зависимости от данных может быть даже возможно использовать Radix Sort, который является O (n), хотя для его использования может потребоваться много данных. Но общая продолжительность выполнения будет чистой O (n). –

+0

P.S. Извините за отправку этого текста в качестве ответа. Он должен был быть комментарием. –