最佳Batcher奇偶合并网络的大小不同于2 ^ n

时间:2015-10-24 16:20:20

标签: algorithm sorting merge sorting-network

现在,我一直在尝试使用最少数量的比较交换单元( size ,而不是深度)实现最大尺寸为32的排序网络。截至目前,我已经能够使用以下资源来生成我的网络:

  • 排序网络0到16:Perl'}" Best"算法。不幸的是,它只提供最知名的网络直到16号。

  • Valsalam和Miikkulainen对17至23号网络进行排序:Algorithm::Networksort module

Baddar撰写的论文Using Symmetry and Evolutionary Search to Minimize Sorting Networks给出了排序网络0到32所需的最小数量的比较交换单元(不是最新的,因为Valsalam和Miikkulainen为尺寸17提供了更好的算法, 18,19,20,21和22)以及用于找到它们的方法:基本上,必须将数组拆分为两个排序,然后使用最知名的排序网络对这些大小进行排序,然后使用奇数合并它们-even merge network(对应Finding Better Sorting Networks的合并步骤。)

Wikipedia页面为Batcher的奇偶合并提供了以下Python实现:

def oddeven_merge(lo, hi, r):
    step = r * 2
    if step < hi - lo:
        yield from oddeven_merge(lo, hi, step)
        yield from oddeven_merge(lo + r, hi, step)
        yield from [(i, i + r) for i in range(lo + r, hi - r, step)]
    else:
        yield (lo, lo + r)

def oddeven_merge_sort_range(lo, hi):
    """ sort the part of x with indices between lo and hi.

    Note: endpoints (lo and hi) are included.
    """
    if (hi - lo) >= 1:
        # if there is more than one element, split the input
        # down the middle and first sort the first and second
        # half, followed by merging them.
        mid = lo + ((hi - lo) // 2)
        yield from oddeven_merge_sort_range(lo, mid)
        yield from oddeven_merge_sort_range(mid + 1, hi)
        yield from oddeven_merge(lo, hi, 1)

def oddeven_merge_sort(length):
    """ "length" is the length of the list to be sorted.
    Returns a list of pairs of indices starting with 0 """
    yield from oddeven_merge_sort_range(0, length - 1)

oddeven_merge步骤已经被隔离,因此很容易单独使用它来生成合并原始数组的两个已排序半部分所需的索引对。但是,此实现仅在数组大小为2时才有效。因此,它只允许我找到大小为32的排序网络所需的最小已知数量的比较交换单元。删除索引对最高指数允许我找到大小为31的等效排序网络,但删除更多对不会产生大于31的最佳已知结果。

Perl的Algorithm::Networksort模块提供了另一种Batcher的奇偶合并实现,它适用于任何大小的数组,而不仅仅是2的幂。因此,我决定看看它是否可以从算法中提取合并步骤。这是Python等价物(它也对应于Knuth在计算机程序设计艺术第3卷中描述的算法):

def oddeven_merge_sort(length):
    t = math.ceil(math.log2(length))

    p = 2 ** (t - 1)

    while p > 0:
        q = 2 ** (t - 1)
        r = 0
        d = p

        while d > 0:
            for i in range(length - d):
                if i & p == r:
                    yield (i, i + d)

            d = q - p
            q //= 2
            r = p
        p //= 2

不幸的是,这个算法对我的眼睛来说似乎有点神秘,我根本无法从中提取合并部分。我设法得到一个合并网络,它给了我24小时排序网络所需的最小数量的比较交换单元,但我使用的技巧没有扩展到任何其他尺寸(根据我的理解,它是绝对不是奇偶合并。)

我已经尝试了一些更多的东西来调整Batcher的奇数偶数mergesort的合并步骤,这个数组的大小不是2的幂,但是我无法找到最着名的对大小为25,26,27,28,29和30的网络进行排序。如何找到合并步骤以找到拼图的缺失部分?

1 个答案:

答案 0 :(得分:3)

Perl算法mentions in a comment,它是Knuth搜索和排序中的算法5.2.2M。

反过来,Knuth提到它将排序的序列与 p = 1 时合并在一起。因此,要生成合并任何N序列的对,只需使用 p = 1 运行算法:

def oddeven_merge_step(length):
    t = math.ceil(math.log2(length))
    q = 2 ** (t - 1)
    r = 0
    d = 1

    while d > 0:
        for i in range(length - d):
            if i & 1 == r:
                yield (i, i + d)

        d = q - 1
        q //= 2
        r = 1

请注意,Batcher的Odd-Even合并步骤需要排序的序列 interleaved (偶数,奇数,偶数,...),但会产生一个连续的排序序列。

例如,对于N = 25,它会生成以下网络:

network