编程珠玑第一章第六题

    xiaoxiao2025-01-16  6

    假设用数组array来进行存储数值及其出现的次数 因为int有32比特,而每个数至多出现10次,又23-1<10<24-1; 又32/4=8,所有说每个int可以存8个数值及其出现的次数;

    一.先说set的实现方法,目的是将数值进行存储且每做一次set个数加一

    (1).下面第一件事就是对每个数值进行分组,由上面可知 0~7用array[0]存储及记录次数;

    8~15用array[1]存储及记录次数,后面的以此类推;也就是给定一个数number,可以通过 number/8(即number>>3)进行分组

    (2)分组之后就是要保存存储数值的个数,并且能够在每次

    set之后加1 假设已经存了8个8,9个9;9个10; 由(1)知 8,9,10均用array[1]进行存储和记录 下面我们画出array[1]此时的前12位,从右向左为从低位到高位; 因为每个数需要四位进行存储,所有我们对array[1]的32位由低到高进行 四位一组划分,分别以0~7表明组号,显然组号可以通过数值number对8取余得到 (注:由于只用了8,9,10只用了前12位,另外的后20位没有画出) 10 9 8 //要存储的数值number 2 1 0 //用哪四位进行存储,number%8得到 1001 1001 1000 //要存储数组number的个数 如果此时想要再存1个10,该怎么办呢? 10 9 8 2 1 0 1001 1001 1000 +0001 0000 0000 =1010 1001 1000 我们对加上的数0001 0000 0000进行观察可知,它是由1向左移8位(2(组号)*4(每组有几位))获得; 从而可以得出一般的结论,即再存一个数是在原有的基础上加上1<<((number%8)*4) ; 至此set部分浮现了

    void set (int number){ array[number/8] += 1<<((number%8)*4); //array[number/8]计算出用哪一个数组元素进行存储 //1<<((number%8)*4)将对应存储数值个数的四位加1 //或者表示 成array[number>>3]+=1<<((number&0x7)*4); }

    二.再说clr方法的实现,目的是将数值的个数置零

    接着一,此时我们有8个8,9个9;10个10; 假如我们想将9的个数清0该怎办?还是画个图进行理解 10 9 8 //要存储的数值number 2 1 0 //用哪四位进行存储,number%8得到 1010 1001 1000 //要存储数组number的个数 此时只要将9对应存储个数的四位清0即可,当然不能影响其他位; 此时只要和(前20位都为1,此处省略不写)1111 0000 1111进行&运算即可 10 9 8 要存储的数值number 2 1 0 用哪四位进行存储,number%8得到 1010 1001 1000 &1111 0000 1111 而1111 0000 1111 可以通过0000 1111 0000取反得到(因为左右移位可以自动补0,所以会利用取反) 而0000 1111 0000可以1111<<4(每组有几位)1(组号)得到 更一般的可以得到1111<<4((number%8))即 0xf<<4*(number%8) 所以最终clr的实现也就明了了

    void clr (int number){ array[number/8]=array[number/8]&(~(0xF<<4*((number%8)))); }

    三就剩一个test了,目的是测试数值存在的个数并返回(0也可以看成一种特别的存在) 接着二,此时我们有8个8,0个9;10个10 ; 10 9 8 要存储的数值number 2 1 0 用哪四位进行存储,number%8得到 1010 0000 1000 要存储数组number的个数 如果我们要测试10存在的个数,就只需要返回对应存储的四位即1010 要想获得1010,有两种方法 (1)先将者四位移到最右边,然后将高位的都置零 即array[number/8]>>(4*(number%8))&(0xF) (2) 先将其他所有位置0,然后将这四位移到最右边 即( array[number/8]& (0xF<<(4*(number%8))) ) >> (4*(number%8)

    int test(int number){ return array[number/8]>>(4*(number%8))&(0xF); }

    **下面再贴一下源码,方便扩展和更改 */ 下面再贴一下源码,方便扩展和更改 / 下面再贴一下源码,方便扩展和更改 / (重要的事情说三遍)

    #include<iostream> using namespace std; #define HMVTS 8 //一个int要存数值的个数 ,how many values to save in each int #define HMBTSN 4 //每个数值需要多少位来保存数值的个数,how many bits to save the number of the specific value #define MASK 0X0F//1111方便得到最后结果 unsigned int array[30]; void set (int number){ array[number/HMVTS] += (1<<((number%HMVTS)*HMBTSN)); } void clr (int number){ array[number/HMVTS]=array[number/HMVTS]&(~(MASK <<HMBTSN*(number%HMVTS))); } int test(int number){ return array[number/HMVTS]>>(HMBTSN*(number%HMVTS))&(MASK); } int main(){ int index; cout<<"未排序的数组为:\n"; unsigned int testArr[20]={ 11,44,56,56,45, 56,56,56,78,49, 60,71,90,117,148, 199,56,56,56,70}; for(index=0;index<20;index++){ set(testArr[index]); cout<<testArr[index]<<" "; } cout<<endl; cout<<"排序结果为:\n"; for(int i=0;i<200;i++){ if(test(i)>0){ for(int j=test(i);j>0;j--){ cout<<i<<" " ; } }} cout<<endl; clr(56); cout<<"清除56后的排序结果为:\n "; for(int i=0;i<200;i++){ if(test(i)>0){ for(int j=test(i);j>0;j--){ cout<<i<<" " ; } }} cout<<endl; }
    转载请注明原文地址: https://ju.6miu.com/read-1295551.html
    最新回复(0)