《编程珠玑》备忘录(开篇)---当每个整数多次出现时

在开篇的习题部分,作者提出了一个延伸问题,即当每个整数最多出现10次的时候,这个排序问题应该如何解决。

尽管这次作者大方地没有限制我们可以使用的内存,但是在设计该程序时还应依照勤俭持家的原则:一个硬币掰开用。由于一个整数最多出现10次,那么我需要4位(bits)来对每个整数出现的频数进行统计。按照一般的设定,一个字符(char)往往包含了8个位,联想到作者之前使用位逻辑运算实现位向量的方法,我在这里照葫芦画瓢,使用一个字符的前后4位分别用于统计两个相邻整数出现的次数。

为了表示起来比较方便,我这里使用CHAR_BIT表示一个字符所包含的位数,如果输入文件包含MAXIMUM个整数,我需要建立的数组大小为((MAXIMUM*4-1)/CHAR_BIT)+1,这个设定方法是我从五岳的博客看来的,这样当MAXIMUM*4非0也非CHAR_BIT的倍数时,最多是有一个char不完全利用,但是不会造成浪费。

#define INTBITS 4
#define MAXMUM 10
#define BITS (MAXMUM*INTBITS-1)/CHAR_BIT+1   

char arr[BITS];

给定一个整数k,用右移运算k>>1可以决定k在数组中的下标;接下来我需要保留这个整数的二进制末位来判断k的频数应当在char的哪一部分,如果末位为0,则将其记在char的0-3位;如果末位为1,则将其记录在char的4-7位。

#define SHIFT 1     //log_2(CHAR_BIT/INTBITS) = 1
#define MASK 0x1    //截取最后一位

void incBit(char *bit, int i)
{
    bit[ i>>SHIFT ] += 1<< ((i&MASK)*INTBITS );
}

同理,当提取统计结果时,可以使用同样的方法得到整数k的出现次数,但是上面不同的是,如果对应的位在4-7位,我就需要对其右移4位来得到最终的答案。最后和0xf进行&运算,可以保证最后得到的就是最后4位。

#define MASK2 0xf  //保留所得结果的最后4位

int compareBit(char *bit, int i)
{
    return (bit[ i>>SHIFT ] >> ((i&MASK)*INTBITS) & MASK2);
}

如果MAXMUM的值设为1千万,那么这个程序所占的内存为4M多,我觉得是可以接受的。作者在答案中也提到依然可以使用多趟算法来减少内存占用,只不过时间要多牺牲一些了。

接下来是我测试时用的程序:

#include <iostream>

#define INTBITS 4
#define SHIFT 1
#define MASK 0x1
#define MASK2 0xf
#define MAXMUM 10
#define BITS (MAXMUM*INTBITS-1)/CHAR_BIT+1

using namespace std;

//用于统计整数i出现的频数
void incBit(char *bit, int i)
{
    bit[ i>>SHIFT ] += 1<<( ( i & MASK ) * INTBITS );
}

//用于提取统计结果
int compareBit(char *bit, int i)
{
    return ( bit[ i>>SHIFT ] >> ( ( i&MASK ) * INTBITS ) & MASK2 );
}

int main()
{
    char arr[BITS];
    int test[8] = { 8, 1, 4, 5, 8, 5, 7, 4};

    for(int i=0; i<BITS; i++){
        arr[i] = 0;
    }

    for(int i=0; i<8; i++){
        incBit(arr, test[i]);
    }

    for(int i=0; i<MAXMUM; i++){
        int countNum = compareBit(arr, i);
        if(countNum>0){
            cout<<i<<"; "<<countNum<<endl;
        }
    }

    return 0;
}
时间: 2024-10-17 21:56:41

《编程珠玑》备忘录(开篇)---当每个整数多次出现时的相关文章

《编程珠玑》阅读小记(1)— 开篇

1. 前言 久闻<编程珠玑>一书的大名,一直没有找到合适的机会深入学习阅读,最近终于得以入手,便决心投入细细的研究,提升一下自己的编程思想与技术.阅读之后才发现,这本书确实一本不可多得的好书.它以计算机领域应用与编程算法相结合,让读者面对实际问题时,不单单局限于考虑该问题的解决方案,而是在入手实践之前能够驻足于考虑,该方案是否符合当前的实际环境,它的时间与空间的消耗是否达到了一个比较好的指标. 通过阅读这本书,很大程度上拓宽了我这样一个菜鸟程序员的视野.对于我来讲,发现要想真正的对书中内容有所

《编程珠玑》高清pdf版

下载地址:网盘下载 作者简介 编辑 Jon Bentley是位于新泽西州Murray Hill的朗讯贝尔实验室计算机科学研究中心的技术委员会委员,Jon自1998年就成为Dr. Dobb's Joumal杂志的特约编辑,他的"编程珠玑"专栏多年来一直是顶级学术杂志Communications of the ACM最风行的特色专栏之一,而本书正是建立在这些专栏的基础之上. 目录 编辑 第一部分 基础 第1章 开篇 1.1 一次友好的对话 1.2 准确的问题描述 1.3 程序设计 1.4

编程珠玑 第2版 pdf

下载地址:网盘下载 内容简介  · · · · · · 本书是计算机科学方面的经典名著.书的内容围绕程序设计人员面对的一系列实际问题展开.作者Jon Bentley 以其独有的洞察力和创造力,引导读者理解这些问题并学会解决方法,而这些正是程序员实际编程生涯中至关重要的.本书的特色是通过一些精心设计的有趣而又颇具指导意义的程序,对实用程序设计技巧及基本设计原则进行了透彻而睿智的描述,为复杂的编程问题提供了清晰而完备的解决思路.本书对各个层次的程序员都具有很高的阅读价值.. 多年以来,当程序员们推选

编程珠玑高清pdf高清版免费下载

下载地址:网盘下载 备用地址:网盘下载 作者简介编辑Jon Bentley是位于新泽西州Murray Hill的朗讯贝尔实验室计算机科学研究中心的技术委员会委员,Jon自1998年就成为Dr. Dobb's Joumal杂志的特约编辑,他的“编程珠玑”专栏多年来一直是顶级学术杂志Communications of the ACM最风行的特色专栏之一,而本书正是建立在这些专栏的基础之上.目录编辑第一部分 基础 第1章 开篇 1.1 一次友好的对话 1.2 准确的问题描述 1.3 程序设计 1.4

《编程珠玑》第一章

一.题目: 如何在1MB的空间里面对一千万个整数进行排序?并且每个数都小于1千万.实际上这个需要1.25MB的内存空间(这里所说的空间是考虑用位图表示法时,每一位代表一个数,则1千万/(1024*1024*8) 约为1.25MB  ). 1MB总共有838,8608个可用位.所以估计也可以在1MB左右的空间里面进行排序了. 分析: 1)基于磁盘的归并排序(耗时间) 2)每个号码采用32位整数存储的话,1MB大约可以存储250 000 个号码,需要读取文件40趟才能把全部整数排序.(耗时间) 3)

编程珠玑第二章

编程珠玑第二章 A题 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中一32位整数. 1.在文件中至少存在这样一个数? 2.如果有足够的内存,如何处理? 3.如果内存不足,仅可以用文件来进行处理,如何处理? 答案: 1.32位整数,包括-2146473648~~2146473647,约42亿个整数,而文件中只有40亿个,必然有整数少了. 2.如果采用位数思想来存放,则32位整数最多需要占用43亿个位.约512MB的内存空间. 可以采用前一章的位处理方法.然后判断每个in

《编程珠玑》阅读小记(9) — 取样问题

问题 本章研究的问题是取样问题,也就是程序设计中的随机数,问题描述如下: 程序的输入包含两个整数m和n,其中 m < n:输出是0~n-1范围内m个随机整数的有序列表,不允许重复.从概率的角度看,我们希望没有重复的有序选择,其中每个选择出现的概率相等. 条件假设: 我们假设有一个能返回很大的随机整数(远远大于m 和 n )的函数bigrand(),以及一个能返回i-j范围内均匀选择的随机整数的randint(i,j). 本章关于这个问题提供了三种算法,接下来详细叙述每个算法的程序实现. 算法1

编程珠玑番外篇之番外篇-O 中间语言和虚拟机漫谈(ZZ)

http://blog.youxu.info/2014/05/11/language-and-vm/ 导言 编程语言的发展历史,总的来说,是一个从抽象机器操作逐步进化为抽象人的思维的过程.机器操作和人的思维如一枚硬币的两面,而语言编译器就像是个双面胶,将这两面粘在一起,保证编程语言源程序和机器代码在行为上等价.当然,人本身并不是一个完美的编译器,不能无错的将思维表达为高级语言程序,这种偏差,即Bug.因为编译器的帮助,我们可以脱离机器细节,只关心表达思维和程序行为这一面. 编程语言的发展日新月异

《编程珠玑》阅读小记(11) — 堆

章节简述 本章主要介绍堆,用该数据结构解决下面两个重要的问题: 排序,采用堆排序算法对n元数组排序,所花的时间不会超过O(nlogn),而且只需要几个字的额外空间: 优先级队列,堆通过插入新元素和提取最小元素这两种操作来维护元素集合,每个操作所需的时间都为O(logn): 本章采用自底向上的组织结构,从细节开始逐步过渡到正题. 堆数据结构 该部分介绍堆数据结构的设计思想. 优先级队列实现向量排序算法 优先级队列提供了一种简单的向量排序算法,优先在优先级队列中依次插入每个元素,然后按序删除它们,程