C AVL比较法,方法是否正确?
我正在使用一个小型的C AVL比较法,方法是否正确?,c,algorithm,performance,avl-tree,C,Algorithm,Performance,Avl Tree,我正在使用一个小型的AVL树库,如您所知,您需要为AVL树节点定义一个比较方法。库将AVL键传递给此方法以对树的元素进行排序。下面是比较方法的语法: int compare(const void* l, const void* r) { } 当l>r时,此函数应返回正值;当l==r时,此函数应返回零;当lr时,此函数应返回负值;第二个函数为l时,此函数应返回负值。一种简单、无UB的比较方法如下: int compare (void* a, void* b) { unsigned int
AVL
树库,如您所知,您需要为AVL
树节点定义一个比较方法。库将AVL
键传递给此方法以对树的元素进行排序。下面是比较方法的语法:
int compare(const void* l, const void* r)
{
}
当
l>r
时,此函数应返回正值;当l==r
时,此函数应返回零;当lr
时,此函数应返回负值;第二个函数为l时,此函数应返回负值。一种简单、无UB的比较方法如下:
int compare (void* a, void* b)
{
unsigned int aa = *(unsigned int*)a;
unsigned int bb = *(unsigned int*)b;
return (aa > bb) - (aa < bb);
}
“我想知道从uint32_t到int的施法是否溢出”-我首先关心的是无符号减法中的下溢,其中r
大于l
。它将“起作用”(它不是UB),但它肯定不会提供您所寻找的答案。仅此一点就让该机制成为了一个糟糕的候选者。@WhozCraig我更新了这个问题以征求您的意见,但减法中的下溢问题可以通过将数据转换为更大的数据类型来解决,例如:(int64_t)*(uint32_t*)l-(int64_t)*(uint32_t*)r
。但铸入法的结果无法解决。我对所有高效的方法都持开放态度你是否真的认为比较函数是一场灾难?与从替换中得到的错误答案相比,正确代码的性能优于错误代码。在进行减法之前,您必须执行一些戏剧性的操作,例如将值强制转换为int64\t
,以便获得所需的有符号结果,并且您需要小心地转换回int
(从int64\t
)以获得正确的有符号结果。你确定这比原来的代码快吗?@JonathanLeffler对int64\t
的转换几乎没有效果,因为现在几乎每个处理器都是64位的。至于速度,我根据汇编代码中的跳转次数进行检查。尽管优化可以创造奇迹,在我提到的示例中,clang创建了无跳转的汇编代码,但使用稍微复杂一点的代码,您会看到很多跳转。请注意,如果您使用类似STL doesgreat results的布尔比较函数,这个问题就会消失。:)但我想知道这个方法是否可以扩展到比较更多的值。例如,如果键是a
,b
,c
,它们通过结构传递到比较函数(如果a
相等,则检查b
,如果b
相等,则检查c
),如果
与否,使用这样的方法代替是否仍然合乎逻辑。@Afshin您可以删除条件,例如<代码>(a?b:c)
应与(b*(a!=0)+c*(a==0)相同
。这可能会编译为跳转自由代码,您可以使用它来构建字典结构比较。但您始终需要根据具体情况进行衡量、比较和决定,因为在某些情况下,直接if
s可能更快。
int compare(const void* l, const void* r)
{
return *(uint32_t*)l - *(uint32_t*)r;
// if you want to overcome underflow in subtraction, you can write it like this:
// return (int64_t)*(uint32_t*)l - (int64_t)*(uint32_t*)r;
// But this will not solve problem with casting to int for returning result
}
`l` points to value | `r` points to value | result
--------------------------------------------------
2 |1 | 1
2 |0xFFFFFFFF | 3
int compare (void* a, void* b)
{
unsigned int aa = *(unsigned int*)a;
unsigned int bb = *(unsigned int*)b;
return (aa > bb) - (aa < bb);
}
mov ecx, DWORD PTR [rdi]
mov edx, DWORD PTR [rsi]
xor eax, eax
cmp ecx, edx
seta al
sbb eax, 0
ret