最小的选择算法 - 关于 /N + 注册 N/ vs. o /n k./ 为了 K << N
我询问了它与算法有关 Top K. 我会这么想 O/n + k log n/ 应该更快,因为好 ... 例如,如果您尝试连接 k = 300 和 n = 100000000, 例如,我们会看到 O/n + k log n/ 较少的。
但是,当我制作基准时 C++, 他告诉我 O /n log k/ 超过B. 2 时间更快。 这是基准测试的完整计划:
一种方法 find_topk 这是建造一个全束的大小 n 期间 o/n/ 然后删除上堆元素 k 时间 o/登记 N/.
一种方法 find_topk2 这是建造一堆尺寸 k /O/k// 这样最大元素位于顶部,然后来自 k 到 n, 比较看任何元素是否小于上部元素,如果是的话,则拔出顶部项目并按将意味着的新项目 n 时间 O/log k/.
两种方法都是非常平等的,所以我不相信实施的任何细节 /例如,创建临时对象等。/ 除了算法和数据集外可能导致差异 /这是随机的/.
我真的可以介绍基准的结果,可以看到这一点 find_topk 实际上导致比较运算符远远超过一次 find_topk2. 但我对理论复杂性的推理更感兴趣..这两个问题。
忽略执行或基准,无论我是错的,还期待那样 O/n + k log n/ 应该比 O/n log k/? 如果我错了,请解释为什么和如何理性,这样我就可以看到 O/n log k/ 实际上更好。
如果我没有误,等待 № 1. 那么为什么我的测试表现相反?
</int></int></int></int></int></int></int></int></int></int></int></cstdlib></ctime></iterator></algorithm></vector></iostream>
但是,当我制作基准时 C++, 他告诉我 O /n log k/ 超过B. 2 时间更快。 这是基准测试的完整计划:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <ctime>
#include <cstdlib>
using namespace std;
int RandomNumber // { return rand//; }
vector<int> find_topk/int arr[], int k, int n/
{
make_heap/arr, arr + n, greater<int>///;
vector<int> result/k/;
for /int i = 0; i < k; ++i/
{
result[i] = arr[0];
pop_heap/arr, arr + n - i, greater<int>///;
}
return result;
}
vector<int> find_topk2/int arr[], int k, int n/
{
make_heap/arr, arr + k, less<int>///;
for /int i = k; i < n; ++i/
{
if /arr[i] < arr[0]/
{
pop_heap/arr, arr + k, less<int>///;
arr[k - 1] = arr[i];
push_heap/arr, arr + k, less<int>///;
}
}
vector<int> result/arr, arr + k/;
return result;
}
int main//
{
const int n = 220000000;
const int k = 300;
srand /time/0//;
int* arr = new int[n];
generate/arr, arr + n, RandomNumber/;
// replace with topk or topk2
vector<int> result = find_topk2/arr, k, n/;
copy/result.begin//, result.end//, ostream_iterator<int>/cout, "\n"//;
return 0;
}
一种方法 find_topk 这是建造一个全束的大小 n 期间 o/n/ 然后删除上堆元素 k 时间 o/登记 N/.
一种方法 find_topk2 这是建造一堆尺寸 k /O/k// 这样最大元素位于顶部,然后来自 k 到 n, 比较看任何元素是否小于上部元素,如果是的话,则拔出顶部项目并按将意味着的新项目 n 时间 O/log k/.
两种方法都是非常平等的,所以我不相信实施的任何细节 /例如,创建临时对象等。/ 除了算法和数据集外可能导致差异 /这是随机的/.
我真的可以介绍基准的结果,可以看到这一点 find_topk 实际上导致比较运算符远远超过一次 find_topk2. 但我对理论复杂性的推理更感兴趣..这两个问题。
忽略执行或基准,无论我是错的,还期待那样 O/n + k log n/ 应该比 O/n log k/? 如果我错了,请解释为什么和如何理性,这样我就可以看到 O/n log k/ 实际上更好。
如果我没有误,等待 № 1. 那么为什么我的测试表现相反?
</int></int></int></int></int></int></int></int></int></int></int></cstdlib></ctime></iterator></algorithm></vector></iostream>
没有找到相关结果
已邀请:
3 个回复
三叔
赞同来自:
例如,如果。 到 ~ n^/1/2/, 然后 o/n k./ 将 o/n 记录 N/ 和 o/N + 注册 N/ 会o。/N + n^/1/2/ 登记 N/ = 关于/N/, 哪个更好。
如果一个 K ~ 报告 N, 对于 o/n k./ = 关于/N 期刊记录 N/ 和 o/N + 注册 N/ = 关于/N/, 哪个更好。 注意 log log 2^1024 = 10, 因此,隐藏的常量 O /n/, 也许更多 log log n 对于任何现实 n.
如果一个 K = 常数,是 o/n k./ = 关于/N/ 和 o/N + 注册 N/ = 关于/N/, 哪个是一样的。
但常量发挥着大作用:例如,构建堆可能包括数组读数 3 次数,同时构建优先级队列长度 k 当你只通过一个传递阵列和一个小的常量 Times log k 搜索。
什么 "better", 因此,虽然我的快速分析趋于表现出来 O/n + k log n/ 效果更好,柔和的假设 k.
例如,如果一个k-非常小的常数 /让我们说 k = 3/, 然后我准备争论这种方法
它工作比实际数据的优先级队列方法更糟糕。
使用渐近分析与思想,最重要的是,在得出结论之前。
郭文康
赞同来自:
如果比较挂钟的时间,而不是比较,你可能会发现基于堆的算法,大桩,通常不会赢得很多比赛,因为它们具有可怕的存储位置 - 现代微处理器上的恒定因素高度依赖于您最终工作的记忆级别 - 检测真实内存芯片中的数据 /或者更糟糕的是,在磁盘上/, 而不是什么 - 然后缓存的水平会慢下来,这非常抱歉,因为我真的很喜欢 heapsort.
冰洋
赞同来自:
std::nth_element/myList.begin//, myList.begin// + 到 myList.end///;
现在 myList 来自位置OT。 0 到 k 将至少有 K 元素。