Допустим, у вас есть массив данных, и вы хотели бы найти его медиану:
double data[MAX_DATA] = ...
Создать массив индексов, и инициализировать каждый индекс к своей собственной позиции, как это:
int index[MAX_DATA];
for (int i = 0 ; i != MAX_DATA ; i++) {
index[i] = i;
}
Теперь реализовать линейную медиана алгоритм со следующими изменениями:
- Когда оригинальный алгоритм сравнивает
data[i]
с data[j]
, заменить сравнения data[index[i]]
к data[index[j]]
- Когда оригинальный алгоритм свопы
data[i]
и data[j]
, поменять index[i]
и index[j]
вместо этого.
Поскольку элементы data
остаются на своем месте все время, модифицированный алгоритм будет производить положение медианы в неизмененном массиве, а не его положение в массиве с элементами переехал в разных местах.
В C++ вы можете реализовать это с помощью указателей вместо индексов, а также использовать std::nth_element
на контейнер указателей, например:
vector<int> data = {1, 5, 2, 20, 10, 7, 9, 1000};
vector<const int*> ptr(data.size());
transform(data.begin(), data.end(), ptr.begin(), [](const int& d) {return &d;});
auto mid = next(ptr.begin(), data.size()/2);
nth_element(ptr.begin(), mid, ptr.end(), [](const int* lhs, const int* rhs) {return *lhs < *rhs;});
ptrdiff_t pos = *mid - &data[0];
cout << pos << endl << data[pos] << endl;
Вот link to a demo on ideone.
Медиана не обязательно должна быть на входе. Пример: медиана [1, 1, 2, 10] равна 1,5 – leemes
Чтобы быть ясным: вы хотите найти медиану в O (n) без изменения списка? Вы не можете сделать копию? – leonbloy
@leonbloy (справа, пренебрежение ...) –