AVL比较方法,是否正确?

时间:2018-07-24 08:06:08

标签: c algorithm performance avl-tree

我正在使用一个小的AVL树库,并且您知道,您需要为AVL树节点定义一个比较方法。库将AVL键传递给此方法以对树的元素进行排序。这是比较方法的语法:

int compare(const void* l, const void* r)
{
}

此函数在l>r时应返回正值,在l==r时应返回零,而在l<r时应返回负值,并且此方法的效率对AVL的效率有很大影响。

现在假定AVL树键是uint32_t。一种简单的方法是使用以下比较功能:

int compare(const void* l, const void* r)
{
    if (*(uint32_t*)l > *(uint32_t*)r)
        return 1;
    if (*(uint32_t*)l < *(uint32_t*)r)
        return -1;
    return 0;
}

但是这种方法的摊销运行时间对于平衡良好的数据是一场灾难,因为 if语句上跳转预测的可能性很高。我通常将此比较写如下:

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
}

这是一个巨大的效率提升。但是考虑到int的返回类型,我想知道从uint32_tint的转换是否溢出或减法下的下溢(或一般情况下其他较大的键数据大小)是否会导致树结构不正确。如果您的键值最多占用31位,那么使用此compare方法,一切都可以正常工作。但是,如果密钥最多占用32位,事情将会变得棘手。例如,查看以下结果:

`l` points to value | `r` points to value | result
--------------------------------------------------
2                   |1                    | 1
2                   |0xFFFFFFFF           | 3

这意味着此比较函数在树的同一侧搜索这两个值,而在第一种情况下,l>r和第二种情况是l<r,并将这两个键都视为无符号值。

我想知道当节点确实存在时,使用此比较方法是否可能不会导致在AVL树中找到一个节点。你怎么看?如果此方法可能找不到节点,那么哪种高效的比较方法将适合这些情况?

最好的问候

1 个答案:

答案 0 :(得分:1)

一种简单的无UB比较方法如下:

int compare (void* a, void* b)
{
    unsigned int aa = *(unsigned int*)a;
    unsigned int bb = *(unsigned int*)b;
    return (aa > bb) - (aa < bb);
}

在x86上,gcc将其编译为以下高效代码(带有-O2):

  mov ecx, DWORD PTR [rdi]
  mov edx, DWORD PTR [rsi]
  xor eax, eax
  cmp ecx, edx
  seta al
  sbb eax, 0
  ret