Python 二进制选择过程

Python 二进制选择过程,python,c,algorithm,binary-search,Python,C,Algorithm,Binary Search,我一直在做一件似乎很简单的事情,这让我发疯。所以如果你喜欢编程挑战。。。继续读下去 我希望能够获得一个数字范围,例如[1:20],并使用类似于二进制serach算法的机制打印值。因此,首先打印最低值(在本例中为1),然后打印中间值(例如,在本例中为10),然后将范围划分为四分之一,并打印1/4和3/4(在本例中为5和15)处的值,然后划分为八分之一,依此类推,直到范围内的所有值都已打印完毕 这一点的应用(这里并没有必要理解)是针对内存页访问机制的,当首先在中间范围访问页时,该机制的行为更有效 对

我一直在做一件似乎很简单的事情,这让我发疯。所以如果你喜欢编程挑战。。。继续读下去

我希望能够获得一个数字范围,例如[1:20],并使用类似于二进制serach算法的机制打印值。因此,首先打印最低值(在本例中为1),然后打印中间值(例如,在本例中为10),然后将范围划分为四分之一,并打印1/4和3/4(在本例中为5和15)处的值,然后划分为八分之一,依此类推,直到范围内的所有值都已打印完毕

这一点的应用(这里并没有必要理解)是针对内存页访问机制的,当首先在中间范围访问页时,该机制的行为更有效

对于这个问题,采用任何数字范围并以上述方式打印值就足够了

有什么想法吗?psuedo代码解决方案就可以了。我会尝试这样做,但到目前为止我所做的一切都没有成功。谢谢

更新:根据要求,示例[1:20]的预期输出如下:1、10、5、15、3、7、12、17、2、4、6、8、11、13、16、18、9、19、20


根据使用的算法,该输出可以以许多类似的方式呈现。但是,我们的想法是先显示一半的值,然后是四分之一,然后是八分之一,然后是十六分之一,等等,忽略之前显示的值

下面是一些Python代码,它们产生与您的示例类似的输出:

def f(低、高):
范围=collections.deque([(低,高)])
而范围:
低,高=范围。popleft()
中=(低+高)//2
产量中期
如果低<中:
范围。追加((低、中))
如果中+1<高:
范围。追加((中+1,高))
例如:

>>> list(f(0, 20))
[10, 5, 15, 2, 8, 13, 18, 1, 4, 7, 9, 12, 14, 17, 19, 0, 3, 6, 11, 16]
low,high
范围不包括端点,这是Python中的惯例,因此结果包含从0到19的数字

该代码使用FIFO存储仍需处理的子范围。FIFO以全量程初始化。在每次迭代中,弹出下一个范围,并生成中点。然后,如果当前范围的下部和上部子范围不为空,则将其附加到FIFO

编辑:这里是C99中完全不同的实现:

#include <stdio.h>

int main()
{
    const unsigned n = 20;
    for (unsigned i = 1; n >> (i - 1); ++i) {
        unsigned last = n;    // guaranteed to be different from all x values
        unsigned count = 1;
        for (unsigned j = 1; j < (1 << i); ++j) {
            const unsigned x = (n * j) >> i;
            if (last == x) {
                ++count;
            } else {
                if (count == 1 && !(j & 1)) {
                    printf("%u\n", last);
                }
                count = 1;
                last = x;
            }
        }
        if (count == 1)
            printf("%u\n", last);
    }
    return 0;
}

(这是我从一开始就打算编写的代码,但我花了一些时间才理解它。)

因为数组已经有了这种结构。您可能希望将数组存储在此表单中并按顺序打印它。对于节点
i
,子节点是
2i+1
2i+2

Hmmm。。。你基本上是在寻找某种类型的空间填充曲线。我几乎可以肯定,你可以通过巧妙的玩弄来做到这一点。您可能想看看Morton Z阶或Ahnentafel索引的索引计算方式,这些索引在一些缓存不经意模板算法中使用。几年前我就看过了,索引与您描述的类似,并通过位旋转完成。

1/2很容易,对吗


那么为什么不递归地做呢,这样1/4就是1/2的1/2,1/8是1/4的1/2吗?

您能为一个示例提供所需的完整输出吗?但您只能使用您分配的页面,对吗?类似问题的这个答案可能会有所帮助:请忽略问题的内存页面分配方面,因为这不是一个熟悉的问题。在我看来,启动该问题是一个错误序列在
1
处,因为每隔一次输出都是一个中点。这看起来很不错。我明天将尝试这种方法,并向您汇报。谢谢。哇,这个答案太完美了。我必须学习deque对象和屈服特性——这两个都非常值得学习。不幸的是,我必须用c代码实现这一点。我需要创建一个子范围结构的FIFO列表,在c中实现起来要困难得多。这强调了python对于此类问题的强大功能。有人给我一些用c语言实现的提示吗?@ZincX:我用一些提示更新了我的答案。为不明显的C代码道歉。我只能说哇!实际上,我用c语言实现了您的原始算法,并使其正常工作,但当然它使用了大量代码。这一秒解决方案工作完美,非常优雅。非常感谢你的帮助@ZincX:我终于找到了一个我满意的算法版本——见我的第二次编辑。空间填充曲线是一个连续函数,从一个区间到单位平方一一映射。这与所提出的问题有什么关系?理想的结果是一种非常不寻常的二进制堆形式(如果您这样称呼它的话):它将是一个二进制搜索树,以通常存储二进制堆的方式存储在数组中。但是,tt不满足heap属性,这一观察结果也不意味着构造此数组的简单方法?如何终止此算法?您如何跟踪已消耗的数字?@SvenMarnach在递归解决方案中,您将序列分成若干部分,然后再细分,依此类推。因此,如果你正确划分,就没有必要记录任何东西。当下一个除法产生空序列时,终止发生。@HonkyTonk:直接递归方法将以错误的顺序产生值。我不确定你们到底在说什么算法,但我想不出一个简单的递归解决方案。
for (int i = 1; n >> (i - 1); ++i) {
    const int m = 1 << i;
    for (int x = n; x < (n << i); x += n << 1) {
        const int k = x & (m - 1);
        if (m - n <= k && k < n)
            printf("%u\n", x >> i);
    }
}