如何解决为什么将排序的键插入 std::set 比插入混洗的键快得多?
我意外地发现将排序的键插入 std::set
比插入混洗的键快得多。这有点违反直觉,因为作为自平衡二叉搜索树的红黑树(我验证了 std::set
在我的系统上是作为红黑树实现的)需要做很多重新平衡操作才能插入一系列已排序的键,因此插入排序的键应该比插入混洗的键花费更多的时间。
但事实是,插入排序的键比插入混洗的键快 15 倍!这是我的测试代码和一些结果:
#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <set>
#include <vector>
using namespace std;
int64_t insertion_time(const vector<int> &keys) {
auto start = chrono::system_clock::Now();
set<int>(keys.begin(),keys.end());
auto stop = chrono::system_clock::Now();
auto elapsed = chrono::duration_cast<chrono::milliseconds>(stop - start);
return elapsed.count();
}
int main() {
size_t test_size;
cout << "test size: ";
cin >> test_size;
vector<int> keys(test_size);
for (int i = 0; i < test_size; ++i) {
keys[i] = i;
}
// whether shuffled case or sorted case took first was irrelevant and results were similar
auto rng = std::default_random_engine {};
shuffle(keys.begin(),keys.end(),rng);
cout << "shuffled: " << insertion_time(keys) << endl;
sort(keys.begin(),keys.end());
cout << "sorted: " << insertion_time(keys) << endl;
return 0;
}
// i7 8700,32 GB RAM,WIN10 2004,g++ -O3 main.cpp
// An interesting observation is that the difference becomes larger as test_size being larger.
// Similar results showed up for my handwritten red-black tree and other
// machines( or other compilers,operating systems etc)
C:\Users\Leon\Desktop\testSetInsertion>a
test size: 1000000
shuffled: 585
sorted: 96
C:\Users\Leon\Desktop\testSetInsertion>a
test size: 3000000
shuffled: 2480
sorted: 296
C:\Users\Leon\Desktop\testSetInsertion>a
test size: 5000000
shuffled: 4805
sorted: 484
C:\Users\Leon\Desktop\testSetInsertion>a
test size: 10000000
shuffled: 11537
sorted: 977
C:\Users\Leon\Desktop\testSetInsertion>a
test size: 30000000
shuffled: 46239
sorted: 3076
有人解释一下吗?我猜这与缓存位置有关,因为在插入排序键时,重新平衡通常涉及最近插入的那些节点。但以上只是我的猜测,我对缓存局部性知之甚少。
解决方法
如果你看https://en.cppreference.com/w/cpp/container/set/set
你可以看到:
复杂性
[..]
2) N log(N)
其中 N = std::distance(first,last)
通常在 N
中线性,如果范围已经按 value_comp() 排序。
我们可以在循环中使用 insert
和 end()
作为提示,这是具有正确提示的摊销常量。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。