您的位置:首页 > 编程语言

[编程珠玑]第一章 开篇

2012-06-12 14:01 351 查看

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)使得此方法可靠性值得信赖!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: