列表中位数的位置
Position of median within a list
我有一个未排序的数组,我需要中位数的位置。我知道有几种算法可以在O(n)内计算给定数组的中位数,但它们都包括某种数组的重新排序,比如中位数的中位数和随机选择。
我对中位数本身不感兴趣,我只对它在数组中的位置感兴趣。
有没有办法在O(n)内完成?跟踪所有的交换将创建一个巨大的开销,所以我正在寻找另一个解决方案。
假设你有一个数据数组,你想找到它的中位数:
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;
下面是生成二级索引数组的工作示例,并通过std::nth_element
和间接比较找到输入数组的中位数
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
int main()
{
// input data, big and expensive to sort or copy
std::string big_data[] = { "hello", "world", "I", "need", "to", "get", "the", "median", "index" };
auto const N = std::distance(std::begin(big_data), std::end(big_data));
auto const M = (N - 1) / 2; // 9 elements, median is 4th element in sorted array
// generate indices
std::vector<int> indices;
auto value = 0;
std::generate_n(std::back_inserter(indices), N, [&](){ return value++; });
// find median of input array through indirect comparison and sorting
std::nth_element(indices.begin(), indices.begin() + M, indices.end(), [&](int lhs, int rhs){
return big_data[lhs] < big_data[rhs];
});
std::cout << indices[M] << ":" << big_data[indices[M]] << "n";
// check, sort input array and confirm it has the same median
std::sort(std::begin(big_data), std::end(big_data));
std::cout << M << ":" << big_data[M] << "n";
}
在线输出。
该算法保证O(N)
复杂度,因为它是std::generate_n
和std::nth_element
的和,它们的输入数据都是O(N)
。
存在一种O(n log n)算法用于跟踪无限数流的中位数。(由于您不想更改列表,您也可以将其视为流。)该算法涉及两个堆;一个总是指向下半部分的最大值,另一个总是指向上半部分的最小值。算法解释在这里:http://www.ardendertat.com/2011/11/03/programming-interview-questions-13-median-of-integer-stream/。
相关文章:
- 在 1.5 秒内找到 3 到 4 个不同整数的中位数超过 2000 万
- C++不同内存位置中的默认数组值
- 十进制的中位数是多少?
- 如何使用第一个、中间和最后一个元素的中位数正确分区?
- 使用 boost::累加器::统计来查找数组的中位数
- 从向量中提取最小值、最大值和中位数的最有效方法是什么
- 如果方法是常量,如何找到向量的中位数?
- 在C++中实现两个大小相等的排序数组的中位数
- 动态分配存储数据在堆中的随机位置中
- 在链接列表前n位置中移动某个节点
- 查找一组循环数据的中位数
- 为什么我的中位数快速选择算法segfault
- 是否可以实施中位数的中位数intreselect而没有掉期或堆的分配
- 两个分类阵列的中位数不同
- C++平均值和中位数绝对偏差返回相同的奇怪符号
- 在磁盘C 上的特定位置中创建队列
- 通过 uva 的中位数程序
- 找到二叉搜索树的中位数,C++
- 双向链表的中位数
- 列表中位数的位置