zoukankan      html  css  js  c++  java
  • Programming Pearls 笔记(1)(续)

         对于我上次提到的问题:怎么开107这么大的数组?这个问题可能是比较弱智的。。。。鄙视自己。。。

         之所以要开107这么大的数组,如果是int a[107],则我们就是用一个int 存储一个信息。这就是大量浪费。而我们知道一个int 有四个字节,在一般的机器上都是32位,即一个int可以表示32个0和1。所以我们数组就可以开成a[1+107/32],这样数组不就小了?

         刚好COLUMN1的习题二就是要求实现这个问题:How would you implement bit vectors usingbitwise logical operations(such as and,or and shift)?

         我在官网找到代码如下,并做了简要分析:

    /* Copyright (C) 1999 Lucent Technologies */
    /* From 'Programming Pearls' by Jon Bentley */

    /* bitsort.c -- bitmap sort from Column 1
    * Sort distinct integers in the range [0..N-1]
    */

    #include <stdio.h>

    #define BITSPERWORD 32//int应该有四个字节,即可以表示32个 0与1
    #define SHIFT 5//左移5位即为除以32
    #define MASK 0x1F//31的十六进制表示
    #define N 10000000//题目要求10^7的大小
    int a[1 + N/BITSPERWORD];//10000000/32,马上把a[10000000]的大小降下来了。
    //i>>SHIFT表示左移五位,“|=”就是a|=b即a=a|b,不用多说。关键是i&MASK等同于i%32,这个结论我会在后面解释。
    void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK)); }//在相应的位置上置1
    void clr(int i) { a[i>>SHIFT] &= ~(1<<(i & MASK)); }//置0
    int test(int i){ return a[i>>SHIFT] & (1<<(i & MASK)); }//取出相应位置上的值

    int main()
    { int i;
    for (i = 0; i < N; i++)
    clr(i);//初始化
    /*
    Replace above 2 lines with below 3 for word-parallel init
    int top = 1 + N/BITSPERWORD;
    for (i = 0; i < top; i++)//另一种初始化,没什么说的
    a[i] = 0;
    */
    while (scanf("%d", &i) != EOF)
    set(i);//对数据的读入
    for (i = 0; i < N; i++)
    if (test(i))
    printf("%d\n", i);//如果在数组里存在i,就输出,明显是从小到大输出的
    return 0;
    }
    //有个结论:m%n,当n为2的x次幕的时候,取余可表示为m&(n-1)
    //分析完这段代码,只想说一句话:神一般的存在啊!!

          刚开始,乍一看这个代码,顿时就懵了。。。。。。完全不知所云。后经查证,慢慢看懂了。关键部分其实就是这样

          

    1 void set(int i) {        a[i/32] |=  (1<<(i % 32)); }
    2 void clr(int i) { a[i/32] &= ~(1<<(i % 32)); }
    3 int test(int i){ return a[i/32] & (1<<(i % 32)); }

          然后我这里证明下那个结论,应该是说明下:

          显然我们知道 : 21=10

                                22=100

                                23=1000(即2的N次幂,就是1后面n个0)

          然后对于任意的m,我们改写成二进制形式,例如:m=1010110,可以写成m=1010000+110。

          记a=1010000,b=110。则m%n=(a+b)%n=a%n+b%n。

          设n=22=100,显然,a%n=0。而b%n ,此时b与n的位数相同,n=(1后面几个零的形式),所以b&(n-1)应该就是余数  即  110%100=10     110&011=10。

          即 1010110%100=10,1010110&0000011=0000010。

          基本上就是这样了,不知道说没说清楚。这也算不上是证明。

          

          分析完这段代码,如果不是对底层汇编比较熟悉的话,是不可能写出来这样的代码的。理论上,移位操作是可以实现任何运算,且效率应该都是较高的。这个bitmap的思想是很好的。



  • 相关阅读:
    HTML5 浏览器设定
    c语言运算符优先级
    Jquery选择器
    asp.net中的<% %>用法
    Jquery技巧
    css选择器
    HTML5 Canvas 参考手册
    具有滑动效果的导航代码
    委托
    kubernetes 1.6 集群实践 (十)
  • 原文地址:https://www.cnblogs.com/xibaohe/p/2367380.html
Copyright © 2011-2022 走看看