Как найти несколько верхних значений из массива?

2

У меня есть массив значений float и вы хотите, чтобы значение и, что более важно, положение максимум четырех значений.

Я первоначально построил систему, чтобы пройти через массив и найти максимальный обычный способ, сравнивая значение в текущей позиции с записанным максимумом до далеки и обновляя переменную позиции, когда max-so-far изменения. Это хорошо работает, O (n) algo, что было очень просто. Позже я узнал, что мне нужно сохранить не только верхнюю ценность, но и тройку лидеров. Я продлил ту же процедуру и усложнил max-so-far в массив из четырех max-so-fars, и теперь код уродливый.

Он по-прежнему работает и все еще достаточно быстро, потому что в процедуру добавлено только тривиальное количество вычислений. он по-прежнему эффективно перемещается по массиву и проверяет каждое значение один раз.

Я делаю это в MATLAB с функцией сортировки, которая возвращает два массива, отсортированный список и соответствующий исходный список позиций. Посмотрев на первые несколько значений, у меня есть именно то, что мне нужно. Я копирую эту функциональность в программу С#.NET 2.0.

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

Он работает хорошо, но теперь я нахожусь в желании пятого максимального значения и вижу, что переписывание макс-тактильной проверки, которая в настоящее время является уродливой неразберихой, если бы утверждения только усугубили уродство. Это будет нормально работать и не замедлить добавление пятого уровня, но я хочу спросить сообщество SO, если есть лучший способ.

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

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

  • 0
    Дубликат: stackoverflow.com/questions/398945/…
  • 0
    Ой, я должен был найти противоположность моего вопроса, прежде чем писать :)
Теги:
arrays
algorithm
max

4 ответа

9
Лучший ответ

Я могу предложить альтернативный алгоритм, который вам придется кодировать:)

Используйте кучу размера 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
  • 0
    FACEPALM Кучи! Спасибо!
  • 0
    +1. Очень хорошее решение, требующее только O (nlog k) времени и O (k) пространства.
2

Я не знаю, какой алгоритм вы используете, но я предлагаю простой. Признавая, что у вас есть массив поплавков 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).

2

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

class IndexAndValue : IComparable<IndexAndValue>
{
    public int index;
    public double value;

    public int CompareTo(IndexAndValue other)
    {
        return value.CompareTo(other.value);
    }
}

Затем вы можете вставить их в список, сохраняя информацию об индексе. Если вы сохраняете только самые большие элементы из списка, тогда ваша эффективность должна быть O (mn).

  • 0
    Я думаю, что вы имели в виду "возвращаемое значение. CompareTo (other.value);"
1

Другой вариант - использовать быстрый выбор. Quick-select возвращает позицию k-го элемента в списке. После того, как у вас есть позиция и значение k-го элемента, перейдите по списку и возьмите каждый элемент, значение которого меньше/больше, чем k-й элемент.

Я нашел реализацию С# быстрого выбора здесь: текст ссылки

Плюсы:

  • O (n + k) среднее время работы.

Минусы:

  • Найденные элементы k не сортируются. Если вы их отсортируете, время выполнения - O (n + logk)
  • Я не проверял это, но я думаю, что для очень маленького k лучшим вариантом является выполнение k пробегов над массивом, каждый раз нахождение следующего наименьшего/наибольшего элемента.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню