我必须使用一种数据结构,使元素保持某种顺序
我可以查询最少元素,也可以有效地插入新元素。所以我选择了
set ( C++ stl)
。 插入需要log(n)
时间,删除最少元素需要log(n)
。
所以我写了以下程序:
#include<iostream>
#include<set>
#include<stdio.h>
using namespace std;
int main()
{
set<int>s1,s2;
set<int>::iterator it;
int tmp,i;
for(i=1;i<=1000000;i++)s1.insert(i);
for(i=1;i<=1000000;i++)
{
it=s1.begin();
s2.insert(*it);
s1.erase(s1.begin());
}
return 0;
}
但是我的机器上需要1.67
秒( i core 3 )我预计会少O(log(1000000)*1000000)
,即2*10^7
我尝试优先级队列< / em>它也给了我相同的表现。那么我应该实现自己的堆以使其更快或有其他方式吗?
答案 0 :(得分:7)
您正在做的是平衡二叉搜索树可能遭受的最困难的事情之一。您将插入项目保留在树的最右侧,并从最左侧继续删除项目,使树始终必须重新平衡。
答案 1 :(得分:4)
有一个名为priority_queue
的模板可以更好地处理您描述的工作负载。它是最大堆,而不是最小堆,但它允许您将自定义比较器作为模板参数传递。它是通过在底层容器上维护堆排序来实现的,该容器通常是vector
。
set
实现为平衡二叉树。这意味着每次插入和查询都会执行log2(n)高度非本地内存访问;把它想象成log2(n)缓存未命中。堆好多了。这些在现代处理器上尤其粗糙,当你驯服你的内存访问模式时,看到一个大的恒定因子加速并不罕见。
答案 2 :(得分:0)
class heap
{
int heap[1000001],siz;
public:
int ini()
{
siz=0;
}
int size()
{
return siz;
}
int top()
{
return heap[1];
}
void insert(int num)
{
siz++;
heap[siz]=num;
int pos=siz,tmp;
while(pos>1)
{
if(heap[pos]<heap[pos/2])
{
tmp=heap[pos];
heap[pos]=heap[pos/2];
heap[pos/2]=tmp;
}
else break;
}
}
void del()
{
if(siz==1)
{
siz=0;
return;
}
heap[1]=heap[siz];
siz--;
int pos=1,tmp;
while(2*pos<=siz)
{
if(2*pos+1<=siz)
{
if(heap[2*pos]<=heap[2*pos+1])
{
if(heap[pos]>heap[2*pos])
{
tmp=heap[pos];
heap[pos]=heap[2*pos];
heap[2*pos]=tmp;
pos=2*pos;
}
else break;
}
else if(heap[2*pos+1]<=heap[2*pos])
{
if(heap[pos]>heap[2*pos+1])
{
tmp=heap[pos];
heap[pos]=heap[2*pos+1];
heap[2*pos+1]=tmp;
pos=2*pos+1;
}
else break;
}
}
else
{
if(heap[pos]>heap[2*pos])
{
tmp=heap[pos];
heap[pos]=heap[2*pos];
heap[2*pos]=tmp;
pos=2*pos;
}
else break;
}
}
}
};
int main()
{
int i,tmp;
heap a1,a2;
a1.ini();a2.ini();
for(i=1;i<=1000000;i++)a1.insert(i);
for(i=1;i<=1000000;i++)
{
tmp=a1.top();
a2.insert(tmp);
a1.del();
}
}
我实现了自己的堆并且在现在0.25秒内完成了同样的操作。我猜它确实是分配和释放内存使得设置变慢。