[编程珠玑]第一章 开篇

1.问题描述

输入:一个最多包含n个整数的文件,文件中的每个整数都小于n,其中n=10^7。输入文件中没有重复的整数。

输出:按升序排列的整数列表

约束:最多有大约1MB的内存空间,有充足的磁盘存储空间可用。


(1)采用外排序;每次读入一部分数据至内存进行排序,然后对各部分进行归并。

(2)采用位图法;用一个一千万位的bit串来表示所有的整数,从左到右每一位分别代表整数1,2,3,4,... ...。初始时,所有bit位都为0,顺序扫描一遍输入数据,对每一个待排序的整数,都将对应的bit位置为1. 最后扫描bit串,将所有为1的位对应的整数输出即可。

#include <stdio.h>
#include <stdlib.h>

#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N/32];
void set(int i) {        a[i>>SHIFT] |=  (1<<(i & MASK)); }
void clr(int i) {        a[i>>SHIFT] &= ~(1<<(i & MASK)); }
int  test(int i){ return a[i>>SHIFT] &   (1<<(i & MASK)); }
int main()
{       int i = 0;
        for(i=0;i<N;i++)
            clr(i);
        while (scanf("%d", &i)) 
			set(i);
        for (i = 0; i < N; i++)
                if (test(i)) 
		   printf("%d\n", i);
        return 0;
}


课后题目:

1. 如果不缺内存,使用一个具有库的语言来实现一种排序算法

c语言:
头文件【#include<stdlib.h>】
函数形式【qsort(s,n,sizeof(s[0]),cmp);】
比较函数【int cmp(const void *a, const void *b) {return(*(int *)a-*(int *)b);} // 升序】

c++语言:
采用STL中提供的sort函数,或者也可以采用set容器进行排序。

python语言:
python中的列表对象带用sort方法,可以直接调用。



2.如何使用为逻辑运算,来实现位向量
void set(int i) {  a[i>>SHIFT] |=  (1<<(i & MASK)); }  
void clr(int i)  {  a[i>>SHIFT] &= ~(1<<(i & MASK)); }  
int  test(int i) {   return a[i>>SHIFT] &   (1<<(i & MASK)); }  
此外也可以直接使用C++中的bitset

3. 略

4.随机生成K个[0,N-1]之间的整数。
(a)分配N个元素的整数数组:A[N],并初始化每个元素为:0,1,2,3,。。。。。。
     对于数组的前K个元素,分别将其和数组的其他元素随机调换,调换的最终结果就是,数组的前K个元素为所需的随机整数
(b)使用概率方法,遍历[0,N-1]中的每一个元素,以一定的概率决定是否输出当前元素。第一个元素0被选中的概率为K/N, 如果第一个元素被选中,那么第二个元素1被选中的概率为K-1/N-1, 如果第一个元素0未被选中,则1被选中的概率为K/N-1, 。。。
代码如下:
select = m
remaining = n
for i = [0, n)
        if (bigrand() % remaining) < select
                print i
                --select
        --remaining


9.
首先,我们应该对题目进行彻底分析---我们需要访问的是一个长度(假设为n)非常大的数组,一般而言对数组中某个元素访问前我们必须要进行初始化,但是当n值非常大而程序对time要求较严格时,对所有的数组元素都进行统一的初始化是不可取的。为了达到程序对time的要求,我们应该对需要访问的元素(它的个数相对于n来说很小)进行初始化。
其次,对元素初始化的判断---为了提高判断的准确性,答案引入了两个数组from和to以及整数top,且对于元素data[i]已初始化的条件是from[i]<top && to[from[i]]==i。

现在让我们来具体分析这些规则是如何被应用的:假设当我们第一次访问的数组元素下标为1时,先判断初始化条件(此时数组from和to都没有初始化,当然time也不允许让我们多管闲事),一般而言from[1]中的随机数是大于top(现在为0)的,但我们不能保证,于是我们加入了第二个判断条件--to[from[1]]==1,对于这个表达式我们两次取随机值且让后者等于1,这样的概率有但几乎为0!因此,data[1]未被初始化,于是执行from[1]=top; to[top]=1; data[1]=0; top++;这样做的目的就是保证以后再次访问data[1]时不需要再初始化(条件满足了直接读取即可)。
最后,对于该方法的可靠性分析---让我们先来分析一下整数top的作用,不难发现,top记录了当前data中已初始化元素的个数,但主要是保证了from中已初始化的元素都小于top(通过from[i]=top; top++),这给我们的判断条件(from[i]<top)提供了一定的可靠性,当然再加上第二到保险(to[from[i]]==i)使得此方法可靠性值得信赖!










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值