Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 高效地找到与位掩码匹配的第一个元素_Algorithm_Search_Optimization_Data Structures_Bitmask - Fatal编程技术网

Algorithm 高效地找到与位掩码匹配的第一个元素

Algorithm 高效地找到与位掩码匹配的第一个元素,algorithm,search,optimization,data-structures,bitmask,Algorithm,Search,Optimization,Data Structures,Bitmask,我有一个N64位整数的列表,其位表示小集合。每个整数最多将k位设置为1。给定一个位掩码,我想在列表中找到与掩码匹配的第一个元素,即元素&mask==element 示例: 如果我的清单是: index abcdef 0 001100 1 001010 2 001000 3 000100 4 000010 5 000001 6 010000 7 100000 8 000000 我的掩码是111000,与掩码匹配的第一个元素位

我有一个N64位整数的列表,其位表示小集合。每个整数最多将k位设置为1。给定一个位掩码,我想在列表中找到与掩码匹配的第一个元素,即
元素&mask==element

示例:

如果我的清单是:

index abcdef
  0   001100
  1   001010
  2   001000
  3   000100
  4   000010
  5   000001
  6   010000
  7   100000
  8   000000
我的掩码是
111000
,与掩码匹配的第一个元素位于索引2

方法1:

线性搜索整个列表。这需要O(N)时间和O(1)空间

方法2:

预先计算所有可能掩码的树,并在每个节点保留该掩码的答案。查询需要O(1)个时间,但需要O(2^64)个空间

问题:

如何在仍然使用合理的空间量的情况下,比O(N)更快地找到与掩码匹配的第一个元素?我可以在预计算中花费多项式时间,因为会有很多查询。关键是k很小。在我的应用程序中,klarge.out创建真正的输出,然后您可以对其进行比较。(掩码是随机生成的,但随机种子是固定的。)然后用实现替换
find_first()
函数


简单的线性搜索比我预期的要快得多。这是因为k很小,因此对于随机掩码,平均很快就会找到匹配项。

构建一个二叉树,如下所示:

  • 每个级别对应一个位
  • 它对应的位在右边,否则在左边
  • 这样就可以在数据库中插入每个数字

    现在,对于搜索:如果掩码中对应的位为1,则遍历两个子项。如果为0,则仅遍历左侧节点。基本上一直遍历树,直到到达叶节点为止(顺便说一句,0是每个掩码的命中率!)

    此树将具有O(N)空间要求

    1(001)、2(010)和5(101)的树的Eg

    后缀树(在位上)将完成此操作,叶节点具有原始优先级:

    000000 -> 8
         1 -> 5
        10 -> 4
       100 -> 3
      1000 -> 2
        10 -> 1
       100 -> 0
     10000 -> 6
    100000 -> 7
    
    其中,如果在掩码中设置了位,则搜索两臂,如果未设置,则仅搜索0臂;您的答案是在叶节点上遇到的最小数目

    您可以通过不按顺序而是通过最大可辨别性遍历位来(略微)改善这一点;在您的示例中,请注意3个元素设置了位2,因此您可以创建

    2:0 0:0 1:0 3:0 4:0 5:0 -> 8
                        5:1 -> 5
                    4:1 5:0 -> 4
                3:1 4:0 5:0 -> 3
            1:1 3:0 4:0 5:0 -> 6
        0:1 1:0 3:0 4:0 5:0 -> 7
    2:1 0:0 1:0 3:0 4:0 5:0 -> 2
                    4:1 5:0 -> 1
                3:1 4:0 5:0 -> 0
    
    在您的示例掩码中,这没有帮助(因为掩码在位2中设置,所以必须遍历bit2==0和bit2==1两个边),但平均而言,这将改善结果(但会以设置和更复杂的数据结构为代价)。如果一些比特比其他比特更有可能被设定,这可能是一个巨大的胜利。如果它们在元素列表中几乎是随机的,那么这根本没有帮助


    如果您被基本上随机设置的位所困扰,那么平均而言,后缀树方法(13倍的加速比)可以让您获得大约
    (1-5/64)^32
    的好处,这可能比使用更复杂的操作带来的效率差异要好(但不要指望它——位掩码很快)。如果列表中的位是非随机分布的,那么使用预计算的位掩码几乎可以做得任意好。

    。形式上仍然是O(N),因为和掩码操作是O(N)。最后一个过程也是O(N),因为它需要找到最低的位集,但这也可以加快速度

    #include <limits.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
      /* For demonstration purposes.
      ** In reality, this should be an unsigned long long */
    typedef unsigned char Thing;
    
    #define BITSPERTHING (CHAR_BIT*sizeof (Thing))
    #define COUNTOF(a) (sizeof a / sizeof a[0])
    
    Thing data[] =
    /****** index abcdef */
    { 0x0c /* 0   001100 */
    , 0x0a /* 1   001010 */
    , 0x08 /* 2   001000 */
    , 0x04 /* 3   000100 */
    , 0x02 /* 4   000010 */
    , 0x01 /* 5   000001 */
    , 0x10 /* 6   010000 */
    , 0x20 /* 7   100000 */
    , 0x00 /* 8   000000 */
    };
    
            /* Note: this is for demonstration purposes.
            ** Normally, one should choose a machine wide unsigned int
            ** for bitmask arrays.
            */
    struct bitmap {
            char data[ 1+COUNTOF (data)/ CHAR_BIT ];
            } nulmaps [ BITSPERTHING ];
    
    #define BITSET(a,i) (a)[(i) / CHAR_BIT ] |= (1u <<  ((i)%CHAR_BIT) )
    #define BITTEST(a,i) ((a)[(i) / CHAR_BIT ] & (1u <<  ((i)%CHAR_BIT) ))
    
    void init_tabs(void);
    void map_empty(struct bitmap *dst);
    void map_full(struct bitmap *dst);
    void map_and2(struct bitmap *dst, struct bitmap *src);
    
    int main (void)
    {
    Thing mask;
    struct bitmap result;
    unsigned ibit;
    
    mask = 0x38;
    init_tabs();
    map_full(&result);
    
    for (ibit = 0; ibit < BITSPERTHING; ibit++) {
            /* bit in mask is 1, so bit at this position is in fact a don't care */
            if (mask & (1u <<ibit))  continue;
            /* bit in mask is 0, so we can only select items with a 0 at this bitpos */
            map_and2(&result, &nulmaps[ibit] );
            }
    
            /* This is not the fastest way to find the lowest 1 bit */
    for (ibit = 0; ibit < COUNTOF (data); ibit++) {
            if (!BITTEST(result.data, ibit) ) continue;
            fprintf(stdout, " %u", ibit);
            }
    fprintf( stdout, "\n" );
    return 0;
    }
    
    void init_tabs(void)
    {
    unsigned ibit, ithing;
    
            /* 1 bits in data that dont overlap with 1 bits in the searchmask are showstoppers.
            ** So, for each bitpos, we precompute a bitmask of all *entrynumbers* from data[], that contain 0 in bitpos.
            */
    memset(nulmaps, 0 , sizeof nulmaps);
    for (ithing=0; ithing < COUNTOF(data); ithing++) {
            for (ibit=0; ibit < BITSPERTHING; ibit++) {
                    if ( data[ithing] & (1u << ibit) ) continue;
                    BITSET(nulmaps[ibit].data, ithing);
                    }
            }
    }
    
            /* Logical And of two bitmask arrays; simular to dst &= src */
    void map_and2(struct bitmap *dst, struct bitmap *src)
    {
    unsigned idx;
    for (idx = 0; idx < COUNTOF(dst->data); idx++) {
            dst->data[idx] &= src->data[idx] ;
            }
    }
    
    void map_empty(struct bitmap *dst)
    {
    memset(dst->data, 0 , sizeof dst->data);
    }
    
    void map_full(struct bitmap *dst)
    {
    unsigned idx;
            /* NOTE this loop sets too many bits to the left of COUNTOF(data) */
    for (idx = 0; idx < COUNTOF(dst->data); idx++) {
            dst->data[idx] = ~0;
            }
    }
    
    #包括
    #包括
    #包括
    #包括
    /*用于演示目的。
    **实际上,这应该是一个未签名的长-长*/
    typedef无符号字符事物;
    #定义BITSPERTHING(CHAR_BIT*sizeof(Thing))
    #定义(a)的计数(a的大小/a的大小[0])
    事物数据[]=
    /******指数abcdef*/
    {0x0c/*0 001100*/
    ,0x0a/*1 001010*/
    ,0x08/*2 001000*/
    ,0x04/*300100*/
    ,0x02/*4 000010*/
    ,0x01/*50万1*/
    ,0x10/*6 010000*/
    ,0x20/*7 100000*/
    ,0x00/*800万*/
    };
    /*注意:这是为了演示。
    **通常,应选择机器范围内的无符号整数
    **用于位掩码阵列。
    */
    结构位图{
    字符数据[1+计数(数据)/字符位];
    }nulmaps[比特比特配对];
    
    #定义位集(a,i)(a)[(i)/CHAR_位]|=(1u这是按位Kd树。每次查找操作通常需要不到64次访问。当前,选择要透视的位(维度)是随机的

    #include <limits.h>
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef unsigned long long Thing;
    typedef unsigned long Number;
    
    unsigned thing_ffs(Thing mask);
    Thing rand_mask(unsigned bitcnt);
    
    #define WANT_RANDOM 31
    #define WANT_BITS 3
    
    #define BITSPERTHING (CHAR_BIT*sizeof(Thing))
    #define NONUMBER ((Number)-1)
    
    struct node {
            Thing value;
            Number num;
            Number nul;
            Number one;
            char pivot;
            } *nodes = NULL;
    unsigned nodecount=0;
    unsigned itercount=0;
    
    struct node * nodes_read( unsigned *sizp, char *filename);
    Number *find_ptr_to_insert(Number *ptr, Thing value, Thing mask);
    
    unsigned grab_matches(Number *result, Number num, Thing mask);
    void initialise_stuff(void);
    
    int main (int argc, char **argv)
    {
    Thing mask;
    Number num;
    unsigned idx;
    
    srand (time(NULL));
    nodes = nodes_read( &nodecount, argv[1]);
    fprintf( stdout, "Nodecount=%u\n", nodecount );
    initialise_stuff();
    
    #if WANT_RANDOM
    mask = nodes[nodecount/2].value | nodes[nodecount/3].value ;
    #else
    mask = 0x38;
    #endif
    
    fprintf( stdout, "\n#### Search mask=%llx\n", (unsigned long long) mask );
    
    itercount = 0;
    num = NONUMBER;
    idx = grab_matches(&num,0, mask);
    fprintf( stdout, "Itercount=%u\n", itercount );
    
    fprintf(stdout, "KdTree search  %16llx\n", (unsigned long long) mask );
    fprintf(stdout, "Count=%u Result:\n", idx);
    idx = num;
    if (idx >= nodecount) idx = nodecount-1;
    fprintf( stdout, "num=%4u Value=%16llx\n"
            ,(unsigned) nodes[idx].num
            ,(unsigned long long) nodes[idx].value
            );
    
    fprintf( stdout, "\nLinear search  %16llx\n", (unsigned long long) mask );
    for (idx = 0; idx < nodecount; idx++) {
            if ((nodes[idx].value & mask) == nodes[idx].value) break;
            }
    fprintf(stdout, "Cnt=%u\n", idx);
    if (idx >= nodecount) idx = nodecount-1;
    fprintf(stdout, "Num=%4u Value=%16llx\n"
            , (unsigned) nodes[idx].num
            , (unsigned long long) nodes[idx].value );
    
    return 0;
    }
    
    void initialise_stuff(void)
    {
    unsigned num;
    Number root, *ptr;
    root = 0;
    
    for (num=0; num < nodecount; num++) {
            nodes[num].num = num;
            nodes[num].one = NONUMBER;
            nodes[num].nul = NONUMBER;
            nodes[num].pivot = -1;
            }
    nodes[num-1].value = 0; /* last node is guaranteed to match anything */
    
    root = 0;
    for (num=1; num < nodecount; num++) {
            ptr = find_ptr_to_insert (&root, nodes[num].value, 0ull );
            if (*ptr == NONUMBER) *ptr = num;
            else fprintf(stderr, "Found %u for %u\n"
                    , (unsigned)*ptr, (unsigned) num );
            }
    }
    
    Thing rand_mask(unsigned bitcnt)
    {struct node * nodes_read( unsigned *sizp, char *filename)
    {
    struct node *ptr;
    unsigned size,used;
    FILE *fp;
    
    if (!filename) {
            size = (WANT_RANDOM+0) ? WANT_RANDOM : 9;
            ptr = malloc (size * sizeof *ptr);
    #if (!WANT_RANDOM)
            ptr[0].value = 0x0c;
            ptr[1].value = 0x0a;
            ptr[2].value = 0x08;
            ptr[3].value = 0x04;
            ptr[4].value = 0x02;
            ptr[5].value = 0x01;
            ptr[6].value = 0x10;
            ptr[7].value = 0x20;
            ptr[8].value = 0x00;
    #else
            for (used=0; used < size; used++) {
                    ptr[used].value = rand_mask(WANT_BITS);
                    }
    #endif /* WANT_RANDOM */
            *sizp = size;
            return ptr;
            }
    
    fp = fopen( filename, "r" );
    if (!fp) return NULL;
    fscanf(fp,"%u\n",  &size );
    fprintf(stderr, "Size=%u\n", size);
    ptr = malloc (size * sizeof *ptr);
    for (used = 0; used < size; used++) {
            fscanf(fp,"%llu\n",  &ptr[used].value );
            }
    
    fclose( fp );
    *sizp = used;
    return ptr;
    }
    
    Thing value = 0;
    unsigned bit, cnt;
    
    for (cnt=0; cnt < bitcnt; cnt++) {
            bit = 54321*rand();
            bit %= BITSPERTHING;
            value |= 1ull << bit;
            }
    return value;
    }
    
    Number *find_ptr_to_insert(Number *ptr, Thing value, Thing done)
    {
    Number num=NONUMBER;
    
    while ( *ptr != NONUMBER) {
            Thing wrong;
    
            num = *ptr;
            wrong = (nodes[num].value ^ value) & ~done;
            if (nodes[num].pivot < 0) { /* This node is terminal */
                    /* choose one of the wrong bits for a pivot .
                    ** For this bit (nodevalue==1 && searchmask==0 )
                    */
                    if (!wrong) wrong = ~done ;
                    nodes[num].pivot  = thing_ffs( wrong );
                    }
            ptr = (wrong & 1ull << nodes[num].pivot) ? &nodes[num].nul : &nodes[num].one;
            /* Once this bit has been tested, it can be masked off. */
            done |= 1ull << nodes[num].pivot ;
            }
    return ptr;
    }
    
    unsigned grab_matches(Number *result, Number num, Thing mask)
    {
    Thing wrong;
    unsigned count;
    
    for (count=0; num < *result; ) {
            itercount++;
            wrong = nodes[num].value & ~mask;
            if (!wrong) { /* we have a match */
                    if (num < *result) { *result = num; count++; }
                    /* This is cheap pruning: the break will omit both subtrees from the results.
                    ** But because we already have a result, and the subtrees have higher numbers
                    ** than our current num, we can ignore them. */
                    break;
                    }
            if (nodes[num].pivot < 0) { /* This node is terminal */
                    break;
                    }
            if (mask & 1ull << nodes[num].pivot) {
                    /* avoid recursion if there is only one non-empty subtree */
                    if (nodes[num].nul >= *result) { num = nodes[num].one; continue; }
                    if (nodes[num].one >= *result) { num = nodes[num].nul; continue; }
                    count += grab_matches(result, nodes[num].nul, mask);
                    count += grab_matches(result, nodes[num].one, mask);
                    break;
                    }
            mask |= 1ull << nodes[num].pivot;
            num = (wrong & 1ull << nodes[num].pivot) ? nodes[num].nul : nodes[num].one;
            }
    return count;
    }
    
    unsigned thing_ffs(Thing mask)
    {
    unsigned bit;
    
    #if 1
    if (!mask) return (unsigned)-1;
    for ( bit=random() % BITSPERTHING; 1 ; bit += 5, bit %= BITSPERTHING) {
            if (mask & 1ull << bit ) return bit;
            }
    #elif 0
    for (bit =0; bit < BITSPERTHING; bit++ ) {
            if (mask & 1ull <<bit) return bit;
            }
    #else
    mask &= (mask-1); // Kernighan-trick
    for (bit =0; bit < BITSPERTHING; bit++ ) {
            mask >>=1;
            if (!mask) return bit;
            }
    #endif
    
    return 0xffffffff;
    }
    
    struct node * nodes_read( unsigned *sizp, char *filename)
    {
    struct node *ptr;
    unsigned size,used;
    FILE *fp;
    
    if (!filename) {
            size = (WANT_RANDOM+0) ? WANT_RANDOM : 9;
            ptr = malloc (size * sizeof *ptr);
    #if (!WANT_RANDOM)
            ptr[0].value = 0x0c;
            ptr[1].value = 0x0a;
            ptr[2].value = 0x08;
            ptr[3].value = 0x04;
            ptr[4].value = 0x02;
            ptr[5].value = 0x01;
            ptr[6].value = 0x10;
            ptr[7].value = 0x20;
            ptr[8].value = 0x00;
    #else
            for (used=0; used < size; used++) {
                    ptr[used].value = rand_mask(WANT_BITS);
                    }
    #endif /* WANT_RANDOM */
            *sizp = size;
            return ptr;
            }
    
    fp = fopen( filename, "r" );
    if (!fp) return NULL;
    fscanf(fp,"%u\n",  &size );
    fprintf(stderr, "Size=%u\n", size);
    ptr = malloc (size * sizeof *ptr);
    for (used = 0; used < size; used++) {
            fscanf(fp,"%llu\n",  &ptr[used].value );
            }
    
    fclose( fp );
    *sizp = used;
    return ptr;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    typedef无符号长事物;
    typedef无符号长数字;
    未签名的对象(对象掩码);
    对象随机掩码(无符号位CNT);
    #定义你想要的是什么
    #定义第3位
    #定义BITSPERTHING(CHAR_BIT*sizeof(Thing))
    #定义非数字((数字)-1)
    结构节点{
    物的价值;
    数字;
    数字nul;
    第一,;
    焦轴;
    }*节点=空;
    无符号nodecount=0;
    无符号itercount=0;
    结构节点*节点\读取(无符号*大小,字符*文件名);
    数字*find_ptr_to_insert(数字*ptr,对象值,对象掩码);
    无符号抓取匹配(Number*结果、Number num、对象掩码);
    void初始化_stuff(void);
    int main(int argc,字符**argv)
    {
    事物面具;
    数字;
    无符号idx;
    srand(时间(空));
    nodes=nodes_read(&nodecount,argv[1]);
    fprintf(标准输出,“Nodecount=%u\n”,Nodecount);
    初始化_stuff();
    #如果你想要随机的
    掩码=节点[nodecount/2]。值|节点[nodecount/3]。值;
    #否则
    掩码=0x38;
    #恩迪夫
    fprintf(标准输出,“\n#####搜索掩码=%llx\n”,(无符号长)掩码);
    itercount=0;
    num=非数字;
    idx=抓取匹配项(&num,0,掩码);
    fprintf(标准输出,“Itercount=%u\n”,Itercount);
    fprintf(stdout,“KdTree搜索%16llx\n”,(无符号长-长)掩码);
    fprintf(标准输出,“计数=%u结果:\n”,idx);
    idx=num;
    如果(idx>=nodecount)idx=nodecount-1;
    fprintf(标准输出,“数值=%4u值=%16l
    
    #include <limits.h>
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef unsigned long long Thing;
    typedef unsigned long Number;
    
    unsigned thing_ffs(Thing mask);
    Thing rand_mask(unsigned bitcnt);
    
    #define WANT_RANDOM 31
    #define WANT_BITS 3
    
    #define BITSPERTHING (CHAR_BIT*sizeof(Thing))
    #define NONUMBER ((Number)-1)
    
    struct node {
            Thing value;
            Number num;
            Number nul;
            Number one;
            char pivot;
            } *nodes = NULL;
    unsigned nodecount=0;
    unsigned itercount=0;
    
    struct node * nodes_read( unsigned *sizp, char *filename);
    Number *find_ptr_to_insert(Number *ptr, Thing value, Thing mask);
    
    unsigned grab_matches(Number *result, Number num, Thing mask);
    void initialise_stuff(void);
    
    int main (int argc, char **argv)
    {
    Thing mask;
    Number num;
    unsigned idx;
    
    srand (time(NULL));
    nodes = nodes_read( &nodecount, argv[1]);
    fprintf( stdout, "Nodecount=%u\n", nodecount );
    initialise_stuff();
    
    #if WANT_RANDOM
    mask = nodes[nodecount/2].value | nodes[nodecount/3].value ;
    #else
    mask = 0x38;
    #endif
    
    fprintf( stdout, "\n#### Search mask=%llx\n", (unsigned long long) mask );
    
    itercount = 0;
    num = NONUMBER;
    idx = grab_matches(&num,0, mask);
    fprintf( stdout, "Itercount=%u\n", itercount );
    
    fprintf(stdout, "KdTree search  %16llx\n", (unsigned long long) mask );
    fprintf(stdout, "Count=%u Result:\n", idx);
    idx = num;
    if (idx >= nodecount) idx = nodecount-1;
    fprintf( stdout, "num=%4u Value=%16llx\n"
            ,(unsigned) nodes[idx].num
            ,(unsigned long long) nodes[idx].value
            );
    
    fprintf( stdout, "\nLinear search  %16llx\n", (unsigned long long) mask );
    for (idx = 0; idx < nodecount; idx++) {
            if ((nodes[idx].value & mask) == nodes[idx].value) break;
            }
    fprintf(stdout, "Cnt=%u\n", idx);
    if (idx >= nodecount) idx = nodecount-1;
    fprintf(stdout, "Num=%4u Value=%16llx\n"
            , (unsigned) nodes[idx].num
            , (unsigned long long) nodes[idx].value );
    
    return 0;
    }
    
    void initialise_stuff(void)
    {
    unsigned num;
    Number root, *ptr;
    root = 0;
    
    for (num=0; num < nodecount; num++) {
            nodes[num].num = num;
            nodes[num].one = NONUMBER;
            nodes[num].nul = NONUMBER;
            nodes[num].pivot = -1;
            }
    nodes[num-1].value = 0; /* last node is guaranteed to match anything */
    
    root = 0;
    for (num=1; num < nodecount; num++) {
            ptr = find_ptr_to_insert (&root, nodes[num].value, 0ull );
            if (*ptr == NONUMBER) *ptr = num;
            else fprintf(stderr, "Found %u for %u\n"
                    , (unsigned)*ptr, (unsigned) num );
            }
    }
    
    Thing rand_mask(unsigned bitcnt)
    {struct node * nodes_read( unsigned *sizp, char *filename)
    {
    struct node *ptr;
    unsigned size,used;
    FILE *fp;
    
    if (!filename) {
            size = (WANT_RANDOM+0) ? WANT_RANDOM : 9;
            ptr = malloc (size * sizeof *ptr);
    #if (!WANT_RANDOM)
            ptr[0].value = 0x0c;
            ptr[1].value = 0x0a;
            ptr[2].value = 0x08;
            ptr[3].value = 0x04;
            ptr[4].value = 0x02;
            ptr[5].value = 0x01;
            ptr[6].value = 0x10;
            ptr[7].value = 0x20;
            ptr[8].value = 0x00;
    #else
            for (used=0; used < size; used++) {
                    ptr[used].value = rand_mask(WANT_BITS);
                    }
    #endif /* WANT_RANDOM */
            *sizp = size;
            return ptr;
            }
    
    fp = fopen( filename, "r" );
    if (!fp) return NULL;
    fscanf(fp,"%u\n",  &size );
    fprintf(stderr, "Size=%u\n", size);
    ptr = malloc (size * sizeof *ptr);
    for (used = 0; used < size; used++) {
            fscanf(fp,"%llu\n",  &ptr[used].value );
            }
    
    fclose( fp );
    *sizp = used;
    return ptr;
    }
    
    Thing value = 0;
    unsigned bit, cnt;
    
    for (cnt=0; cnt < bitcnt; cnt++) {
            bit = 54321*rand();
            bit %= BITSPERTHING;
            value |= 1ull << bit;
            }
    return value;
    }
    
    Number *find_ptr_to_insert(Number *ptr, Thing value, Thing done)
    {
    Number num=NONUMBER;
    
    while ( *ptr != NONUMBER) {
            Thing wrong;
    
            num = *ptr;
            wrong = (nodes[num].value ^ value) & ~done;
            if (nodes[num].pivot < 0) { /* This node is terminal */
                    /* choose one of the wrong bits for a pivot .
                    ** For this bit (nodevalue==1 && searchmask==0 )
                    */
                    if (!wrong) wrong = ~done ;
                    nodes[num].pivot  = thing_ffs( wrong );
                    }
            ptr = (wrong & 1ull << nodes[num].pivot) ? &nodes[num].nul : &nodes[num].one;
            /* Once this bit has been tested, it can be masked off. */
            done |= 1ull << nodes[num].pivot ;
            }
    return ptr;
    }
    
    unsigned grab_matches(Number *result, Number num, Thing mask)
    {
    Thing wrong;
    unsigned count;
    
    for (count=0; num < *result; ) {
            itercount++;
            wrong = nodes[num].value & ~mask;
            if (!wrong) { /* we have a match */
                    if (num < *result) { *result = num; count++; }
                    /* This is cheap pruning: the break will omit both subtrees from the results.
                    ** But because we already have a result, and the subtrees have higher numbers
                    ** than our current num, we can ignore them. */
                    break;
                    }
            if (nodes[num].pivot < 0) { /* This node is terminal */
                    break;
                    }
            if (mask & 1ull << nodes[num].pivot) {
                    /* avoid recursion if there is only one non-empty subtree */
                    if (nodes[num].nul >= *result) { num = nodes[num].one; continue; }
                    if (nodes[num].one >= *result) { num = nodes[num].nul; continue; }
                    count += grab_matches(result, nodes[num].nul, mask);
                    count += grab_matches(result, nodes[num].one, mask);
                    break;
                    }
            mask |= 1ull << nodes[num].pivot;
            num = (wrong & 1ull << nodes[num].pivot) ? nodes[num].nul : nodes[num].one;
            }
    return count;
    }
    
    unsigned thing_ffs(Thing mask)
    {
    unsigned bit;
    
    #if 1
    if (!mask) return (unsigned)-1;
    for ( bit=random() % BITSPERTHING; 1 ; bit += 5, bit %= BITSPERTHING) {
            if (mask & 1ull << bit ) return bit;
            }
    #elif 0
    for (bit =0; bit < BITSPERTHING; bit++ ) {
            if (mask & 1ull <<bit) return bit;
            }
    #else
    mask &= (mask-1); // Kernighan-trick
    for (bit =0; bit < BITSPERTHING; bit++ ) {
            mask >>=1;
            if (!mask) return bit;
            }
    #endif
    
    return 0xffffffff;
    }
    
    struct node * nodes_read( unsigned *sizp, char *filename)
    {
    struct node *ptr;
    unsigned size,used;
    FILE *fp;
    
    if (!filename) {
            size = (WANT_RANDOM+0) ? WANT_RANDOM : 9;
            ptr = malloc (size * sizeof *ptr);
    #if (!WANT_RANDOM)
            ptr[0].value = 0x0c;
            ptr[1].value = 0x0a;
            ptr[2].value = 0x08;
            ptr[3].value = 0x04;
            ptr[4].value = 0x02;
            ptr[5].value = 0x01;
            ptr[6].value = 0x10;
            ptr[7].value = 0x20;
            ptr[8].value = 0x00;
    #else
            for (used=0; used < size; used++) {
                    ptr[used].value = rand_mask(WANT_BITS);
                    }
    #endif /* WANT_RANDOM */
            *sizp = size;
            return ptr;
            }
    
    fp = fopen( filename, "r" );
    if (!fp) return NULL;
    fscanf(fp,"%u\n",  &size );
    fprintf(stderr, "Size=%u\n", size);
    ptr = malloc (size * sizeof *ptr);
    for (used = 0; used < size; used++) {
            fscanf(fp,"%llu\n",  &ptr[used].value );
            }
    
    fclose( fp );
    *sizp = used;
    return ptr;
    }