How do the bit manipulations in this bit-sorting code work?

前端 未结 6 1559
时光取名叫无心
时光取名叫无心 2021-01-31 22:20

Jon Bentley in Column 1 of his book programming pearls introduces a technique for sorting a sequence of non-zero positive integers using bit vectors.

I have taken the p

6条回答
  •  名媛妹妹
    2021-01-31 23:09

    The bit magic is used as a special addressing scheme that works well with row sizes that are powers of two.

    If you try understand this (note: I rather use bits-per-row than bits-per-word, since we're talking about a bit-matrix here):

    // supposing an int of 1 bit would exist...
    int1 bits[BITSPERROW * N]; // an array of N x BITSPERROW elements
    
    // set bit at x,y:
    int linear_address = y*BITSPERWORD + x;
    bits + linear_address = 1; // or 0
    // 0 1 2 3 4 5 6 7 8 9 10 11 ... 31
    // . . . . . . . . . .  .  .       .  
    // . . . . X . . . . .  .  .       .  -> x = 4, y = 1 => i = (1*32 + 4)
    

    The statement linear_address = y*BITSPERWORD + x also means that x = linear_address % BITSPERWORD and y = linear_address / BITSPERWORD.

    When you optimize this in memory by using 1 word of 32 bits per row, you get the fact that a bit at column x can be set using

    int bitrow = 0;
    bitrow |= 1 << (x);
    

    Now when we iterate over the bits, we have the linear address, but need to find the corresponding word.

    int column = linear_address % BITSPERROW;
    int bit_mask =  1 << column; // meaning for the xth column, 
                                 // you take 1 and shift that bit x times
    int row    = linear_address / BITSPERROW;
    

    So to set the i'th bit, you can do this:

    bits[ i%BITSPERROW ] |= 1 << (linear_address / BITSPERROW );
    

    An extra gotcha is, that the modulo operator can be replaced by a logical AND, and the / operator can be replaced by a shift, too, if the second operand is a power of two.

    a % BITSPERROW == a & ( BITSPERROW - 1 ) == a & MASK
    a / BITSPERROW == a >> ( log2(BITSPERROW) ) == a & SHIFT
    

    This ultimately boils down to the very dense, yet hard-to-understand-for-the-bitfucker-agnostic notation

    a[ i >> SHIFT ] |= ( 1 << (i&MASK) );
    

    But I don't see the algorithm working for e.g. 40 bits per word.

提交回复
热议问题