C++ 树迭代器,你能进一步优化它吗?
作为我最初关于这段代码的一小部分的问题的后续,我决定问一个后续问题,看看你是否能比我们目前提出的做得更好 下面的代码迭代二叉树(left/right=child/next)。我确实相信这里有一个条件更少的空间(C++ 树迭代器,你能进一步优化它吗?,c++,optimization,iteration,binary-tree,C++,Optimization,Iteration,Binary Tree,作为我最初关于这段代码的一小部分的问题的后续,我决定问一个后续问题,看看你是否能比我们目前提出的做得更好 下面的代码迭代二叉树(left/right=child/next)。我确实相信这里有一个条件更少的空间(downboolean)。最快的答案获胜 cnt语句可以是多个语句,因此让我们确保它只出现一次 child()和next()成员函数的速度大约是hasChild()和hasNext()操作的30倍 保持迭代为什么不是递归解决方案 void processTree (const BaseNo
down
boolean)。最快的答案获胜
cnt
语句可以是多个语句,因此让我们确保它只出现一次child()
和next()
成员函数的速度大约是hasChild()和hasNext()操作的30倍void processTree (const BaseNodePtr ¤t, unsigned int & cnt )
{
cnt++;
if (current->hasChild())
processTree(current->child());
if (current->hasNext())
processTree(current->next());
}
既然shared\u ptr
似乎是您的瓶颈,为什么不改进它呢?你在使用线程吗?如果没有,则取消定义符号BOOST\u的线程数。共享\u ptr
引用计数由互斥锁保护,这可能是性能缓慢的原因
为什么不将数据结构更改为不同时使用shared\ptr
?自己管理原始指针?也许可以使用作用域\u ptr
替代?为什么不使用递归解决方案
void processTree (const BaseNodePtr ¤t, unsigned int & cnt )
{
cnt++;
if (current->hasChild())
processTree(current->child());
if (current->hasNext())
processTree(current->next());
}
既然shared\u ptr
似乎是您的瓶颈,为什么不改进它呢?你在使用线程吗?如果没有,则取消定义符号BOOST\u的线程数。共享\u ptr
引用计数由互斥锁保护,这可能是性能缓慢的原因
为什么不将数据结构更改为不同时使用shared\ptr
?自己管理原始指针?也许可以使用作用域\u ptr
来代替?创建一个“nextvisit”函数,并继续调用该函数,以简化代码;接下来,对共享指针使用常量引用iso值语义。。。这可能会为您节省宝贵的共享ptr副本:
// define the order of visitation in here
BaseNodePtr& next( const BaseNodePtr& p ) {
if( p->hasChild() ) return p->child();
if( p->hasNext() ) return p->next();
BaseNodePtr ancestor = p->parent();
while( ancestor != 0 && !ancestor->hasNext() ) ancestor = ancestor->parent();
return ancestor;
}
void processTree( const BaseNodePtr& p, unsigned int& cnt ) {
while( p != NULL ) {
++cnt;
p = next(p);
}
}
但为了可读性、清晰性、可维护性。。。看在上帝的份上,使用递归。除非你的堆栈不够大。创建一个“nextvisit”函数,并不断调用它,以简化代码;接下来,对共享指针使用常量引用iso值语义。。。这可能会为您节省宝贵的共享ptr副本:
// define the order of visitation in here
BaseNodePtr& next( const BaseNodePtr& p ) {
if( p->hasChild() ) return p->child();
if( p->hasNext() ) return p->next();
BaseNodePtr ancestor = p->parent();
while( ancestor != 0 && !ancestor->hasNext() ) ancestor = ancestor->parent();
return ancestor;
}
void processTree( const BaseNodePtr& p, unsigned int& cnt ) {
while( p != NULL ) {
++cnt;
p = next(p);
}
}
但为了可读性、清晰性、可维护性。。。看在上帝的份上,使用递归。除非你的堆栈不够大。当回答以“不要那样做”来回避问题时,我讨厌。
说有一种方法可以移除下壁。。。这真的会对执行时间产生真正的影响吗?我们讨论的是少量CPU操作和堆栈上的一些额外字节
如果需要加快调用速度,请将重点放在加快child()和parent()调用上。否则你就是在浪费时间(伊莫霍)
编辑:
也许可以遍历一次树(使用这个“慢”代码),然后按照所需的顺序在树中构建一个指针数组。稍后使用此“索引”
我想说的是,我认为你从错误的角度来处理优化问题。当答案以“不要那样做”来回避这个问题时,我恨你。但我来了
说有一种方法可以移除下壁。。。这真的会对执行时间产生真正的影响吗?我们讨论的是少量CPU操作和堆栈上的一些额外字节
如果需要加快调用速度,请将重点放在加快child()和parent()调用上。否则你就是在浪费时间(伊莫霍)
编辑:
也许可以遍历一次树(使用这个“慢”代码),然后按照所需的顺序在树中构建一个指针数组。稍后使用此“索引”
我想说的是,我认为您从错误的角度进行优化。这里介绍了如何只调用一个递归调用,而不是两个递归调用:
void processTree (const BaseNodePtr ¤t, unsigned int & cnt )
{
for(bool gotNext = true; gotNext; current = current->next()) {
cnt++;
if (current->hasChild())
processTree(current->child());
gotNext = current->hasNext();
}
}
下面是如何只调用一个递归调用而不是两个递归调用:
void processTree (const BaseNodePtr ¤t, unsigned int & cnt )
{
for(bool gotNext = true; gotNext; current = current->next()) {
cnt++;
if (current->hasChild())
processTree(current->child());
gotNext = current->hasNext();
}
}
为了提高最终的速度,您需要对内存中的节点进行排序,以便它们按照访问顺序存储在连续块中
e、 如果你有一棵树,定义如下
1
/ \
2 3
/ \ /\
4 5 6 7
/\ / /\
8 9 10 11 12
/ \ \
13 14 15
然后,如上所述的访问功能将按以下顺序访问节点
1
2
4
8
13
14
9
5
3
6
10
7
11
12
15
现在,如果您将内存中的节点排序为15个分配的连续块,并按照上面演示的顺序存储节点,那么您通常将访问具有“”的节点。这可以根据节点结构的大小提高缓存命中率,从而加快运行速度
创建一种快速迭代的方法,只访问树中的所有节点一次,不递归
unsigned int g_StackDepth = 0;
BaseNodePtr* g_Stack[MAX_STACK_DEPTH];
void processTree (BaseNodePtr root, unsigned int & cnt )
{
g_Stack[g_StackDepth++] = root;
while( g_StackDepth > 0 )
{
BaseNodePtr curr = g_Stack[--g_StackDepth];
cnt++;
if ( curr->HasNext() )
{
g_Stack[g_StackDepth++] = curr->Next();
}
if ( curr->HasChild() )
{
g_Stack[g_StackDepth++] = curr->Child();
}
}
}
据我所知,结合上述订购,您应该可以获得最佳速度
显然,这是有局限性的,因为您必须知道堆栈可以提前增长多大。尽管您可以通过使用std::vector来解决这个问题。然而,使用std::vector将消除上述迭代方法提供的所有优点
希望对您有所帮助:)要想获得最高的速度,您需要做的是对内存中的节点进行排序,以便它们按照访问顺序存储在连续块中
e、 如果你有一棵树,定义如下
1
/ \
2 3
/ \ /\
4 5 6 7
/\ / /\
8 9 10 11 12
/ \ \
13 14 15
然后,如上所述的访问功能将按以下顺序访问节点
1
2
4
8
13
14
9
5
3
6
10
7
11
12
15
现在,如果您将内存中的节点排序为15个分配的连续块,并按照上面演示的顺序存储节点,那么您通常将访问具有“”的节点。这可以根据节点结构的大小提高缓存命中率,从而加快运行速度
创建一种快速迭代的方法,只访问树中的所有节点一次,不递归
unsigned int g_StackDepth = 0;
BaseNodePtr* g_Stack[MAX_STACK_DEPTH];
void processTree (BaseNodePtr root, unsigned int & cnt )
{
g_Stack[g_StackDepth++] = root;
while( g_StackDepth > 0 )
{
BaseNodePtr curr = g_Stack[--g_StackDepth];
cnt++;
if ( curr->HasNext() )
{
g_Stack[g_StackDepth++] = curr->Next();
}
if ( curr->HasChild() )
{
g_Stack[g_StackDepth++] = curr->Child();
}
}
}
据我所知,结合上述订购,您应该可以获得最佳速度
显然,这是有局限性的,因为您必须知道堆栈可以提前增长多大。尽管您可以通过使用std::vector来解决这个问题。但是,使用std::vector会