У меня есть массив значений float и вы хотите, чтобы значение и, что более важно, положение максимум четырех значений.
Я первоначально построил систему, чтобы пройти через массив и найти максимальный обычный способ, сравнивая значение в текущей позиции с записанным максимумом до далеки и обновляя переменную позиции, когда max-so-far изменения. Это хорошо работает, O (n) algo, что было очень просто. Позже я узнал, что мне нужно сохранить не только верхнюю ценность, но и тройку лидеров. Я продлил ту же процедуру и усложнил max-so-far в массив из четырех max-so-fars, и теперь код уродливый.
Он по-прежнему работает и все еще достаточно быстро, потому что в процедуру добавлено только тривиальное количество вычислений. он по-прежнему эффективно перемещается по массиву и проверяет каждое значение один раз.
Я делаю это в MATLAB с функцией сортировки, которая возвращает два массива, отсортированный список и соответствующий исходный список позиций. Посмотрев на первые несколько значений, у меня есть именно то, что мне нужно. Я копирую эту функциональность в программу С#.NET 2.0.
Я знаю, что я мог бы сделать что-то подобное с объектом List, и что объект List имеет встроенную процедуру сортировки, но я не верю, что он может указать мне исходные позиции, и это действительно то, что я получаю после,
Он работает хорошо, но теперь я нахожусь в желании пятого максимального значения и вижу, что переписывание макс-тактильной проверки, которая в настоящее время является уродливой неразберихой, если бы утверждения только усугубили уродство. Это будет нормально работать и не замедлить добавление пятого уровня, но я хочу спросить сообщество SO, если есть лучший способ.
Сортировка всего списка требует гораздо больше вычислений, чем мой текущий метод, но я не думаю, что это будет проблемой, так как список "всего" один или две тысячи плавающих; поэтому, если есть процедура сортировки, которая может вернуть исходные позиции, это было бы идеально.
В качестве фона этот массив является результатом преобразования Фурье на килобайт волнового файла, поэтому положения максимальных значений соответствуют частотам пиков выборки данных. Я был доволен четырьмя первыми, но вижу, что действительно нужно собрать пятерку или шесть для более точной классификации образцов.
Я могу предложить альтернативный алгоритм, который вам придется кодировать:)
Используйте кучу размера K, где K обозначает количество верхних элементов, которые вы хотите сохранить. Инициализируйте это для первых элементов K вашего исходного массива. Для всех элементов N - K перемещайте массив, вставляя по мере необходимости.
proc top_k (array<n>, heap<k>)
heap <- array<1..k-1>
for each (array<k..n-1>)
if array[i] > heap.min
heap.erase(heap.min)
heap.insert(array[i])
end if
end for
Я не знаю, какой алгоритм вы используете, но я предлагаю простой.
Признавая, что у вас есть массив поплавков f
и максимум capacity
чисел, вы можете сделать следующее:
int capacity = 4; // number of floats you want to retrieve
float [] f; // your float list
float [] max_so_far = new float[capacity]; // max so far
// say that the first 'capacity' elements are the biggest, for now
for (int i = 0; i < capacity; i++)
max_so_far[i] = i;
// for each number not processed
for (int i = capacity; i < f.length; i++)
{
// find out the smallest 'max so far' number
int m = 0;
for (int j = 0; j < capacity; j++)
if (f[max_so_far[j]] < f[max_so_far[m]])
m = j;
// if our current number is bigger than the smallest stored, replace it
if (f[i] > f[max_so_far[m]])
max_so_far[m] = i;
}
К концу алгоритма вы будете иметь индексы наибольших сохраненных элементов
в max_so_far
.
Обратите внимание, что если значение capacity
растет, оно будет немного медленнее, чем
альтернативный, который сортирует список, отслеживая исходные позиции.
Помните, что сортировка принимает O (nlog n) сравнения, тогда как этот алгоритм принимает O (ncapacity).
Вы все равно можете использовать свою идею списка - элементы, которые вы ввели в список, могут быть структурой, в которой хранятся как индекс, так и значение; но сортируется только по значению, например:
class IndexAndValue : IComparable<IndexAndValue>
{
public int index;
public double value;
public int CompareTo(IndexAndValue other)
{
return value.CompareTo(other.value);
}
}
Затем вы можете вставить их в список, сохраняя информацию об индексе. Если вы сохраняете только самые большие элементы из списка, тогда ваша эффективность должна быть O (mn).
Другой вариант - использовать быстрый выбор. Quick-select возвращает позицию k-го элемента в списке. После того, как у вас есть позиция и значение k-го элемента, перейдите по списку и возьмите каждый элемент, значение которого меньше/больше, чем k-й элемент.
Я нашел реализацию С# быстрого выбора здесь: текст ссылки
Плюсы:
Минусы: